在演示者类中测试协程

时间:2019-07-05 14:46:30

标签: android unit-testing kotlin android-testing kotlin-coroutines

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

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

演示者也在扩展此接口:

interface CoroutinePresenter: CoroutineScope {

val job: Job

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

fun stopAllActiveJobs() {
    coroutineContext.cancelChildren()
}

暂停功能定义如下:

 suspend fun execute() : Boolean = withContext(Dispatchers.IO) {
    return@withContext class.foo()
}

应用程序中的所有功能均按预期工作,但是当我尝试编写一些单元测试时,我注意到无论何时我调用 launch 中的一段代码,线程都会切换,但测试不会等待执行。这是测试的实现:

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

我还添加了建议的库来测试kotlinx-coroutines-test,但结果仍然与之相同。我也尝试遵循this的建议,并实施类似this的方法,但还是没有运气。 我认为问题在于,只要在演示者中调用 launch 时实际创建了另一个线程,而测试实际上并不知道如何等待它。我还尝试返回一个 Job 并调用job.join(),但失败了,返回一个NullPointerException

希望你们能帮助我。

2 个答案:

答案 0 :(得分:0)

我找到了一个解决方案: 在this教程之后,我已经设置了两者

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

然后通过在测试中的presenter语句中运行runBlocking类的整个 launch 块。该问题还与暂挂函数内部未报告的异常有关,该异常实际上不是 mock ,但在我眼中是不可见的。

现在一切正常。

答案 1 :(得分:0)

首先,我强烈建议您将coroutineContext作为这样的参数:

  class CoroutinePresenter(coroutineContext: CoroutineContext): CoroutineScope {
         init{
               _coroutineContext = coroutineContext
          }

         override val coroutineContext: CoroutineContext
                get() = _coroutineContext

         // Your Methods

    }

在您的真实环境中:

 @YourScope
    @Provides
    fun providesCoroutinePresenter(coroutineContext:CoroutineContext ){
        return CoroutinePresenter()
    }
    @YourScope
    @Provides
    fun providesCoroutineContext(){
        return  Dispatchers.Main + job
    }

在单元测试期间:

    @Before
    fun setUp() {
       coroutinePresenter  CoroutinePresenter(Dispatchers.Unconfined)
    }

    @Test
    fun `Should do something`(){
         //WHEN
         coroutinePresenter.doSomething(params)
         //THEN
         do your assertions
    }

有关更多信息,请查看 SOLID原则,在这种情况下,请查看 D