如何使用MockK测试挂起功能?

BRD*_*oid 15 android unit-testing mockito kotlin mockk

我正在为我的数据存储库层编写一个单元测试,它只是调用一个接口。我使用 Kotlin、协程和 MockK 进行单元测试。在MockK中,我如何验证我已经调用过apiServiceInterface.getDataFromApi()并且只发生过一次?我应该将代码放在 runBlocking 中吗?

这是我的代码:

单元测试

import com.example.breakingbad.api.ApiServiceInterface
import com.example.breakingbad.data.DataRepository
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import org.junit.Test
Run Code Online (Sandbox Code Playgroud)

存储库

class DataRepositoryTest {
    @MockK
    private lateinit var apiServiceInterface: ApiServiceInterface

    @InjectMockKs
    private lateinit var dataRepository: DataRepository

    @Test
    fun getCharacters() {
            val respose = dataRepository.getCharacters()
            verify { apiServiceInterface.getDataFromApi() }
    }
}

    class DataRepository @Inject constructor(
    private val apiServiceInterface: ApiServiceInterface
) {
    suspend fun getCharacters(): Result<ArrayList<Character>> = kotlin.runCatching{
        apiServiceInterface.getDataFromApi()
    }
}
Run Code Online (Sandbox Code Playgroud)

界面

interface ApiServiceInterface {
    @GET("api/characters")
    suspend fun getDataFromApi(): ArrayList<Character>
}
Run Code Online (Sandbox Code Playgroud)

小智 12

我认为你应该更喜欢使用runTestor 而不是runBlockingrunBlockingTest简单地告诉你这三个。

  1. runBlocking允许您通过阻止新的协程来调用挂起函数,并且它会阻止当前线程直到完成。

  2. runBlockingTest将立即执行挂起函数,跳过任何延迟并立即进入协程块,runBlocking这与等待延迟量不同

自 kotlinx.coroutines 1.6.0 发布以来,由于迁移指南中列出的这些原因,runBlockingTest已被弃用。runTest

  1. runTest()将自动跳过对delay()的调用并处理未捕获的异常。与 runBlockingTest() 不同,它将等待异步回调来处理某些代码在未与测试模块集成的调度程序中运行的情况。

我希望这能回答您在这三个选项中选择什么来测试您的暂停功能的问题。你的代码看起来像这样——:

@Test
fun getCharacters() = runTest {
    val response = dataRepository.getCharacters()
    
    coVerify { apiServiceInterface.getDataFromApi() }
}
Run Code Online (Sandbox Code Playgroud)

另请注意,正如 David 上面提到的,因为 getDataFromApi() 也是异步/挂起函数,所以您必须使用 coVerify 而不是 verify 来模拟它。


L3n*_*L3n 4

是的,您应该将dataRepository.getCharacters()调用放在runBlocking.

并且verify应该替换为coVerify.

最后,测试应该如下所示:

@Test
fun getCharacters() {
    val respose = runBlocking { dataRepository.getCharacters() }
    
    coVerify { apiServiceInterface.getDataFromApi() }
}
Run Code Online (Sandbox Code Playgroud)

另外,由于您想验证它只发生一次,因此您需要coVerify使用精确的参数进行调用coVerify(exactly = 1)