【发布时间】:2019-05-22 19:56:50
【问题描述】:
我已经开始为我的 MVP Android 项目编写单元测试,但是我依赖于协程的测试间歇性地失败(通过日志记录和调试,我确认验证有时会提前发生,当然添加 delay 可以解决这个问题)
我尝试过使用runBlocking 进行包装,并且我从org.jetbrains.kotlinx:kotlinx-coroutines-test 中发现了Dispatchers.setMain(mainThreadSurrogate),但尝试了这么多组合到目前为止都没有取得任何成功。
abstract class CoroutinePresenter : Presenter, CoroutineScope {
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreate() {
super.onCreate()
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
class MainPresenter @Inject constructor(private val getInfoUsecase: GetInfoUsecase) : CoroutinePresenter() {
lateinit var view: View
fun inject(view: View) {
this.view = view
}
override fun onResume() {
super.onResume()
refreshInfo()
}
fun refreshInfo() = launch {
view.showLoading()
view.showInfo(getInfoUsecase.getInfo())
view.hideLoading()
}
interface View {
fun showLoading()
fun hideLoading()
fun showInfo(info: Info)
}
}
class MainPresenterTest {
private val mainThreadSurrogate = newSingleThreadContext("Mocked UI thread")
private lateinit var presenter: MainPresenter
private lateinit var view: MainPresenter.View
val expectedInfo = Info()
@Before
fun setUp() {
Dispatchers.setMain(mainThreadSurrogate)
view = mock()
val mockInfoUseCase = mock<GetInfoUsecase> {
on { runBlocking { getInfo() } } doReturn expectedInfo
}
presenter = MainPresenter(mockInfoUseCase)
presenter.inject(view)
presenter.onCreate()
}
@Test
fun onResume_RefreshView() {
presenter.onResume()
verify(view).showLoading()
verify(view).showInfo(expectedInfo)
verify(view).hideLoading()
}
@After
fun tearDown() {
Dispatchers.resetMain()
mainThreadSurrogate.close()
}
}
我认为 runBlocking 块应该强制所有子 coroutineScopes 在同一个线程上运行,强制它们在继续验证之前完成。
【问题讨论】:
-
能否提供你
Presenter的代码和完整的测试类代码。 -
@Sergey 我已按要求扩展了我的代码示例,希望对您有所帮助
标签: android kotlin junit mockito kotlin-coroutines