在Kotlin中,如何模拟包装回调的暂停函数?

时间:2018-08-03 13:16:15

标签: callback kotlin mocking mockito kotlinx.coroutines

假设有一个带有回调的接口:

interface SomeInterface {
    fun doSomething(arg: String, callback: (Exception?, Long) -> Unit)
}

我将其扩展为这样的暂停函数:

suspend fun SomeInterface.doSomething(arg: String): Long = suspendCoroutine { cont ->
    this.doSomething(arg) { err, result ->
        if (err == null) {
            cont.resume(result)
        } else {
            cont.resumeWithException(err)
        }
    }
}

我想在测试中模拟这个,但是失败了。 理想情况下,我想使用这样的东西:

@Test
fun checkService() {
    runBlocking {
        val myService = mock<SomeInterface>()
        whenever(myService.doSomething(anyString())).thenReturn(1234L)
        val result = myService.doSomething("")
        assertEquals(result, 1234L)
    }
}

上面的语法失败,并带有模仿异常,因为它期望回调的匹配器。

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
2 matchers expected, 1 recorded:

如何模拟这样的暂停功能? 如果不可能使用类似的语法,我该如何使用所需的参数进行模拟调用,以使在我的代码中使用的suspend变体在测试期间返回所需的结果?

更新: 当它是扩展功能时,似乎是不可能的。根据{{​​3}}的评论,我认为这是因为扩展名只是静态函数,超出了Mockito的能力。

当suspend函数是成员函数时,它将按照我的原始语法正常工作。

这里是要点,其中包含一些演示代码: Marko Topolnik

2 个答案:

答案 0 :(得分:1)

我建议您使用MockK进行测试,这对协程更友好。

要模拟协程,可以使用coEveryreturns,如下所示:

val interface = mockk<SomeInterface>()
coEvery { a.doSomething(any()) } returns Outcome.OK

答案 1 :(得分:1)

何时需要

在...上。确实返回..

并且方法被暂停,使用 mockito ,您可以使用此方法:

  • 使用此lib mockito-kotlin
  • 模拟您的对象,将其命名为myObject(myObject具有名为isFoo的暂停方法)

然后:

 myObject.stub {
    onBlocking { isFoo() }.doReturn(true)
}