android - 单元测试协程 runBlockingTest : This job has not completed yet

标签 android unit-testing kotlin kotlin-coroutines mockk

请在下面找到使用协程替换回调的函数:

override suspend fun signUp(authentication: Authentication): AuthenticationError {
    return suspendCancellableCoroutine {
        auth.createUserWithEmailAndPassword(authentication.email, authentication.password)
            .addOnCompleteListener(activityLifeCycleService.getActivity()) { task ->
                if (task.isSuccessful) {
                    it.resume(AuthenticationError.SignUpSuccess)
                } else {
                    Log.w(this.javaClass.name, "createUserWithEmail:failure", task.exception)
                    it.resume(AuthenticationError.SignUpFail)
                }
            }
    }
}

现在我想对这个功能进行单元测试。我正在使用 Mockk :
  @Test
  fun `signup() must be delegated to createUserWithEmailAndPassword()`() = runBlockingTest {

      val listener = slot<OnCompleteListener<AuthResult>>()
      val authentication = mockk<Authentication> {
        every { email } returns "email"
        every { password } returns "pswd"
      }
      val task = mockk<Task<AuthResult>> {
        every { isSuccessful } returns true
      }

      every { auth.createUserWithEmailAndPassword("email", "pswd") } returns
          mockk {
            every { addOnCompleteListener(activity, capture(listener)) } returns mockk()
          }

    service.signUp(authentication)

      listener.captured.onComplete(task)
    }

不幸的是,由于以下异常,此测试失败:java.lang.IllegalStateException: This job has not completed yet
我试图替换 runBlockingTestrunBlocking但测试似乎在无限循环中等待。

有人可以帮我解决这个 UT 吗?

提前致谢

最佳答案

可以在 this 中看到邮政:

This exception usually means that some coroutines from your tests were scheduled outside the test scope (more specifically the test dispatcher).



而不是执行此操作:
private val networkContext: CoroutineContext = TestCoroutineDispatcher()

private val sut = Foo(
  networkContext,
  someInteractor
)

fun `some test`() = runBlockingTest() {
  // given
  ...

  // when
  sut.foo()

  // then
  ...
}

创建一个通过测试调度程序的测试范围:
private val testDispatcher = TestCoroutineDispatcher()
private val testScope = TestCoroutineScope(testDispatcher)
private val networkContext: CoroutineContext = testDispatcher

private val sut = Foo(
  networkContext,
  someInteractor
)

然后在测试中执行 testScope.runBlockingTest
fun `some test`() = testScope.runBlockingTest {
  ...
}


另见 Craig Russell 的 "Unit Testing Coroutine Suspend Functions using TestCoroutineDispatcher"

关于android - 单元测试协程 runBlockingTest : This job has not completed yet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61224047/

相关文章:

kotlin - 类什么时​​候是数据类?

android - 如何在编译 APK(Release) 时排除文件夹

Android Toasts 在某些手机上获得触摸事件,而在其他手机上则没有

java - 是否有任何模拟框架允许监视父类(super class)方法?

unit-testing - 有没有像糟糕的单元测试这样的事情?

c# - .NET 工具 : Extract Interface and Implement Wrapper Class

android - fragment 作为内部类

android - Android中状态栏的高度

android - 如何创建一项服务,即收听音量按钮?

android - android 的图标分辨率限制