Я разрабатываю игрушечное приложение для Android, используя Kotlin (Coroutine).
Я знаком с Rx больше, чем с Coroutine.
Я чувствую, что Coroutine сложнее, чем Rx.
Во всяком случае, вот мой код Presenter:
class NowPlayingPresenter(
private val view: NowPlayingContract.View,
private val getMovies: GetNowPlayingMovies,
private val uiContext: CoroutineContext = Dispatchers.Main,
ioContext: CoroutineContext = Dispatchers.IO
) : NowPlayingContract.Presenter, CoroutineScope, AnkoLogger {
override val coroutineContext: CoroutineContext = Job() + ioContext
override fun unsubscribe() {
coroutineContext.cancel()
}
override fun getMoviesNowPlaying() {
view.showProgressBar(View.VISIBLE)
view.hideError()
launch {
try {
val movies = getMovies.get()
// 'movies' is always null!!! I don't know why...
withContext(uiContext) {
view.showProgressBar(View.GONE)
if (movies.isNullOrEmpty()) {
view.onError(R.string.err_movies_not_exists)
} else {
view.onMoviesLoaded(movies)
}
}
} catch (t: Throwable) {
view.showProgressBar(View.GONE)
view.onError(R.string.err_get_movies_failed)
error("[Y.M.] getMoviesNowPlaying - failed: ${t.message}", t)
}
}
}
}
Вот мой код GetNowPlayingMovies, это просто интерфейс:
interface GetNowPlayingMovies {
suspend fun get(): List<SimpleMovie>
}
И ниже мой тестовый код JUnit:
class MyDataPresenterTest {
@Mock
private lateinit var mockView: NowPlayingContract.View
@Mock
private lateinit var getMovies: GetNowPlayingMovies
private lateinit var presenter: NowPlayingPresenter
private lateinit var inOrder: InOrder
private val mockMovie1 = SimpleMovie("posterpath1", false, "2019-03-01", 10, "hello world1", 10f)
private val mockMovie2 = SimpleMovie("posterpath2", true, "2019-03-02", 20, "hello world2", 9f)
private val mockMovie3 = SimpleMovie("posterpath3", false, "2019-03-03", 30, "hello world3", 8f)
private val mockMovie4 = SimpleMovie("posterpath4", false, "2019-03-04", 40, "hello world4", 7f)
private val mockMovie5 = SimpleMovie("posterpath5", false, "2019-03-05", 50, "hello world5", 6f)
private val mockMovies: List<SimpleMovie> = listOf(
mockMovie1,
mockMovie2,
mockMovie3,
mockMovie4,
mockMovie5
)
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
inOrder = Mockito.inOrder(mockView)
presenter = NowPlayingPresenter(mockView, getMovies, Dispatchers.Unconfined, Dispatchers.Unconfined)
}
@Test
fun getMoviesNowPlayingTest() = runBlocking {
`when`(getMovies.get()).thenReturn(mockMovies)
presenter.getMoviesNowPlaying()
inOrder.verify(mockView).showProgressBar(View.VISIBLE)
inOrder.verify(mockView).hideError()
inOrder.verify(mockView).showProgressBar(View.GONE)
inOrder.verify(mockView).onMoviesLoaded(mockMovies)
}
}
Кто-нибудь, помогите мне, пожалуйста?
Вот мой полный код: https://github.com/yoonhok524/Android-Sandbox/tree/master/kotlin-coroutine
Я попытался применить «Чистую архитектуру» в этом проекте, поэтому код не легко читать... может быть...
Вы можете поделиться сообщением о неудачном тесте?
r2rek, я уже написал сообщение об ошибке в коде Presenter в качестве комментария.
Ircover, Это просто список класса данных, когда я проверял его в тестовом коде, он не был нулевым.
В моем случае и условностях....
launch {
val data = withContext(ioContext) {
repository.get(id)
}
withContext(uiContext) {
view?.onDataLoaded(data)
}
}Я применил ваш код, но это не удалось с сообщением об ошибке: Исключение в потоке "main @coroutine # 1" java.lang.IllegalStateException: не удалось инициализировать модуль с диспетчером Main. Для тестов можно использовать Dispatchers.setMain из модуля kotlinx-coroutines-test
Вы используете Mockito 1.x. Если вы делаете макет для функции приостановки, используйте последний Mockito. https://stackoverflow.com/a/53101077/4639261
Было бы полезно, если бы вы разместили создание
mockDataобъектного кода.