Android 使用 mockK 测试视图模型
Android testing view model with mockK
我正在尝试使用 mockK 库测试我的视图模型。但我不知道该怎么做。这是我的class。我有一个用例和一个存储库:
@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(...)
的 return 值是什么。您可以这样做: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:
A relaxed mock is the mock that returns some simple value for all functions. This allows to skip specifying behavior for each case, while still allowing to stub things you need. For reference types, chained mocks are returned.
val getRecentPhotosUseCase:GetRecentPhotosUseCase= mockk(relaxed = true)
我正在尝试使用 mockK 库测试我的视图模型。但我不知道该怎么做。这是我的class。我有一个用例和一个存储库:
@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(...)
的 return 值是什么。您可以这样做: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:
A relaxed mock is the mock that returns some simple value for all functions. This allows to skip specifying behavior for each case, while still allowing to stub things you need. For reference types, chained mocks are returned.
val getRecentPhotosUseCase:GetRecentPhotosUseCase= mockk(relaxed = true)