如何使用 MockK 测试挂起函数?

How to test suspend function using MockK?

提问人:BRDroid 提问时间:9/1/2021 最后编辑:TomerikooBRDroid 更新时间:7/30/2022 访问量:9788

问:

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

这是我的代码:

单元测试

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

存储 库

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()
    }
}

接口

interface ApiServiceInterface {
    @GET("api/characters")
    suspend fun getDataFromApi(): ArrayList<Character>
}
Android 单元测试 Kotlin mockito mockk

评论


答:

4赞 David Gomes 11/28/2021 #1

是的,您应该将呼叫放在 .dataRepository.getCharacters()runBlocking

并且应该替换为 .verifycoVerify

最后,测试应如下所示:

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

此外,由于您要验证它只发生过一次,因此您需要使用 exact 参数进行调用coVerifycoVerify(exactly = 1)

10赞 hiteshchopra11 7/30/2022 #2

我认为您应该更喜欢使用 而不是 or 。简单介绍一下这三个。runTestrunBlockingrunBlockingTest

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

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

由于迁移指南中列出的这些原因,kotlinx.coroutines 1.6.0 版本已被弃用,取而代之的是。runBlockingTestrunTest

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

我希望这能回答您在这 3 个中选择什么来测试您的挂起函数的问题。您的代码将如下所示 - :

@Test
fun getCharacters() = runTest {
    val response = dataRepository.getCharacters()
    
    coVerify { apiServiceInterface.getDataFromApi() }
}

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

评论

0赞 David Gomes 8/5/2022
不知道那些在测试中调用挂起函数的函数,我个人从来不需要它,但很高兴知道 👍