使用 mockK 的 Android 测试视图模型

问题描述

我正在尝试使用 mockK 库测试我的视图模型。但我无法弄清楚如何做到这一点。这是我的课。我有一个用例和一个存储库:

    @ExperimentalCoroutinesApi
class MainviewmodelTest {

    private val getRecentPhotosUseCase:GetRecentPhotosUseCase= mockk()
    private val recentPhotosRepository:RemoteRecentPhotosRepository= mockk()
    private val mainviewmodel by lazy { RecentPhotosviewmodel(getRecentPhotosUseCase) }
    @ExperimentalCoroutinesApi
    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()

    @get:Rule
    var instantTaskExecutorRule = InstantTaskExecutorRule()

    @Before
    fun setupBefore(){
        startKoin {
            androidContext(App.getInstance())
            if (BuildConfig.DEBUG) androidLogger(Level.DEBUG)
            modules(appModules + domainModules + dataModules)
        }
    }

    @Test
    fun `get recent photo success`(){
         val map: MutableMap<String,String> = HashMap()
    map["format"] = "json"
    map["method"] = "flickr.photos.getRecent1"
    map["nojsoncallback"]="1"
    map["per_page"]="20"
    map["page"]= "1"
    val recentPhotoResponse = mockk<RecentPhotos>()
    //1- Mock calls
    every { runBlocking {recentPhotosRepository.getRecentPhotos(map)} } returns Success(recentPhotoResponse)
    mainviewmodel.viewState.observeForever {  }
    runBlocking {mainviewmodel.getRecentPhotos(map)}
    val getRecentPhotoSuccess= mainviewmodel.viewState.value
    MatcherAssert.assertthat(
        "Received result [$getRecentPhotoSuccess] & mocked ${OnSuccess(recentPhotoResponse)} must be matches on each other!",getRecentPhotoSuccess,CoreMatchers.`is`(OnSuccess(recentPhotoResponse))
    )
    }
}

但是当我运行测试时,它给了我这个错误

io.mockk.MockKException: no answer found for: GetRecentPhotosUseCase(#1).invoke({per_page=20,method=flickr.photos.getRecent1,format=json,page=1,nojsoncallback=1},continuation {})

解决方法

你需要告诉mockk getRecentPhotosUseCase.function(...) 的返回值是什么。你这样做:every { mock.call(...) } returns Value。您可以将 any() 作为参数,也可以使用具体值:

every { getRecentPhotosUseCase.function(any(),any(),...) } returns YourResultValue
// or
every { getRecentPhotosUseCase.function(per_page = 20,...) } returns YourResultValue

或者,如果您不想模拟 GetRecentPhotosUseCase 的结果(可能是因为它与您的测试场景无关),您可以使用 relaxed mock

轻松的模拟是为所有函数返回一些简单值的模拟。这允许跳过为每种情况指定行为,同时仍然允许存根您需要的东西。对于引用类型,返回链接的模拟。

val getRecentPhotosUseCase:GetRecentPhotosUseCase= mockk(relaxed = true)