在 Presenter 中测试协程 class

Testing coroutines in the presenter class

我正在努力测试我的演示者,它正在从存储库层调用一个挂起的函数,如下所示:

 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,但结果还是一样。我也尝试关注 suggestion and also implementing something like this 但仍然没有成功。 我认为问题是每当在演示者中调用 launch 时实际创建另一个线程,而测试实际上不知道如何等待它。我还尝试 return 一个 Job 并调用 job.join() 但它失败了 NullPointerException.

希望大家能帮帮我。

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

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

并通过 运行 整个 launchpresenter class 在测试中的 runBlocking 语句中。该问题还与挂起函数内的未报告异常有关,该函数实际上不是 mocked 但我看不到它。

现在一切正常。

首先,我强烈建议像这样给你的 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