测试挂起协程

Testing suspend corotuine

我正在尝试使用协程来处理我的登录服务的异步代码。不幸的是,登录服务的实现必须在完成时接受回调。在这些回调之一发生之前​​,我不希望此 login() 函数完成。

这是我的:

fun login(): Outcome = runBlocking {
    suspendCoroutine<Outcome> { continuation ->
        loginService.login(
                onLoginSuccess = {
                    // do some stuff
                    continuation.resume(Outcome.SUCCESS)
                },
                onLoginFailure = {
                    // handle failure case
                    continuation.resume(Outcome.FAILURE)
                }
        )
    }
}

我的问题是我的测试从未完成。我认为正在发生的事情是延续块本身不是 运行。我也尝试将对 uut.login() 的调用包装在 runBlocking 中,但没有帮助。这是我的测试代码(使用 Spek):

describe("when login") {

    val successCaptor: ArgumentCaptor<() -> Unit> = TestHelpers.argumentCaptorForClass()
    val failureCaptor: ArgumentCaptor<() -> Unit> = TestHelpers.argumentCaptorForClass()

    var result: Outcome? = null

    beforeEachTest {
        doNothing().whenever(mockLoginService)?.login(capture(successCaptor), capture(failureCaptor))
        result = uut?.execute()
    }

    it("logs in with the login service") {
        verify(mockLoginService)?.login(any(), any())
    }

    describe("and the login succeeds") {

        beforeEachTest {
            successCaptor.value.invoke()
        }

        // other tests...

        it("returns an outcome of SUCCESS") {
            expect(result).to.equal(Outcome.SUCCESS)
        }
    }

    describe("and the login fails") {
        beforeEachTest {
            failureCaptor.value.invoke()
        }

        // other tests...

        it("returns an outcome of FAILURE") {
            expect(result).to.equal(Outcome.FAILURE)
        }
    }
}

基本上,我想断言 login() 方法根据发生的情况返回成功或失败结果。

有什么想法吗?

当然,我发帖后就想通了。如果有兴趣,这是我在测试中所做的:

describe("when login") {

    val successCaptor: ArgumentCaptor<() -> Unit> = TestHelpers.argumentCaptorForClass()
    val failureCaptor: ArgumentCaptor<() -> Unit> = TestHelpers.argumentCaptorForClass()

    var result: Outcome? = null

    describe("and the login succeeds") {

        beforeEachTest {
            whenever(mockLoginService?.login(capture(successCaptor), capture(failureCaptor))).thenAnswer {
                successCaptor.value.invoke()
            }
            result = uut?.execute()
        }

        it("logs in with the login service") {
            verify(mockLoginService)?.login(any(), any())
        }

        it("returns an outcome of SUCCESS") {
            expect(result).to.equal(Outcome.SUCCESS)
        }
    }

    describe("and the login fails") {
        beforeEachTest {
            whenever(mockLoginService?.login(capture(successCaptor), capture(failureCaptor))).thenAnswer {
                failureCaptor.value.invoke()
            }
            result = uut?.execute()
        }

        it("logs in with the login service") {
            verify(mockLoginService)?.login(any(), any())
        }

        // other tests

        it("returns an outcome of FAILURE") {
            expect(result).to.equal(Outcome.FAILURE)
        }
    }
}