单元测试协程 runBlockingTest: This job has not complete yet

新手上路,请多包涵

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

 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

我试图用 runBlockingTest runBlocking 但测试似乎在无限循环中等待。

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

提前致谢

原文由 suns9 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
1 个回答

这篇 文章可以看出:

此异常通常意味着测试中的某些协程被安排在测试范围之外(更具体地说是测试调度程序)。

而不是执行此操作:

 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 的 “使用 TestCoroutineDispatcher 对协程暂停函数进行单元测试”

原文由 azizbekian 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏