在演示者类中测试协程

Mar*_*rco 8 android unit-testing kotlin android-testing kotlin-coroutines

我正在努力测试我的演示者,该演示者从存储库层调用暂停的函数,如下所示:

 override fun viewCreated() {
        launch {
            val hasPermission = permissionChecker.execute() //suspended function
            if (hasPermission) {
                foo()
            } else {
                view.bar()
            }
         }
Run Code Online (Sandbox Code Playgroud)

演示者还在扩展此接口:

interface CoroutinePresenter: CoroutineScope {

val job: Job

override val coroutineContext: CoroutineContext
    get() = Dispatchers.Main + job

fun stopAllActiveJobs() {
    coroutineContext.cancelChildren()
}
Run Code Online (Sandbox Code Playgroud)

暂停功能定义如下:

 suspend fun execute() : Boolean = withContext(Dispatchers.IO) {
    return@withContext class.foo()
}
Run Code Online (Sandbox Code Playgroud)

一切都在应用程序中按预期工作,但是当我尝试编写一些单元测试时,我注意到,每当我在启动时调用一段代码时,线程都会切换,但是测试不会等待执行。这是测试的执行:

@Test
fun `Test of Suspended Function`() = runBlocking {
    presenter.viewCreated()
    then(view).should().bar()
    ...
}
Run Code Online (Sandbox Code Playgroud)

我还添加了建议的测试库,kotlinx-coroutines-test但结果仍然相同。我也试图按照这一建议,并实施像这样,但仍然没有运气。我认为问题在于在演示者中调用启动时实际创建了另一个线程,而测试实际上并不知道如何等待它。我还尝试返回Job并调用,job.join()但失败了NullPointerException

希望你们能帮助我。

Mar*_*rco 2

我找到了一个解决方案:按照教程,我已经设置了两者

@Before
fun setup() {
    Dispatchers.setMain(Dispatchers.Unconfined)
    ...
}
@After
fun tearDown() {
    Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
}
Run Code Online (Sandbox Code Playgroud)

并通过在测试中的语句内运行类的整个启动块。该问题还与挂起函数内未报告的异常有关,该异常实际上没有被模拟,但我的眼睛看不到它。presenterrunBlocking

现在一切正常。