我想测试服务器不返回响应的情况,然后我们触发下一个网络调用(例如搜索查询)。
所以我们基本上在ViewModel和Retrofit方法中有一个方法
interface RetrofitApi {
@GET("Some Url")
suspend fun getVeryImportantStuff(): String
}
class TestViewModel(private val api: RetrofitApi) : ViewModel() {
private var askJob: Job? = null
fun load(query: String) {
askJob?.cancel()
askJob = viewModelScope.launch {
val response = api.getVeryImportantStuff()
//DO SOMETHING WITH RESPONSE
}
}
}
而且我想在询问新查询而旧查询没有返回时测试案例。对于响应返回测试很容易的情况
@Test
fun testReturnResponse() {
runBlockingTest {
//given
val mockApi:RetrofitApi = mock()
val viewModel = TestViewModel(mockApi)
val response = "response from api"
val query = "fancy query"
whenever(mockApi.getVeryImportantStuff()).thenReturn(response)
//when
viewModel.load(query)
//then
//verify what happens
}
}
但是我不知道如何模拟未返回的暂停功能,并在这样触发新请求时测试案例
@Test
fun test2Loads() {
runBlockingTest {
//given
val mockApi:RetrofitApi = mock()
val viewModel = TestViewModel(mockApi)
val response = "response from api"
val secondResponse = "response from api2"
val query = "fancy query"
whenever(mockApi.getVeryImportantStuff())
.thenReturn(/* Here return some fancy stuff that is suspend* or something like onBlocking{} stub but not blocking but dalayed forever/)
.thenReturn(secondResponse)
//when
viewModel.load(query)
viewModel.load(query)
//then
//verify that first response did not happens , and only second one triggered all the stuff
}
}
任何想法?
编辑:我并没有真正附加到模仿者,任何模仿库都将是好的:)问候Wojtek
看起来您想在服务器超时或类似情况发生时测试方案。
在这种情况下,您可以在进行模拟时说,首先尝试它返回对象,然后在第二次执行时抛出诸如java.net.ConnectException: Connection timed out
之类的异常。
whenever(mockApi.getVeryImportantStuff())
.thenReturn(someObjet)
.thenThrow(ConnectException("timed out"))
并且这应该可行,但是您必须在ViewModel中进行try / catch块,这并不理想。我建议您添加其他抽象。
您可以选择Repository
或UseCase
,还是您想在其中移动网络呼叫的任何模式/名称。然后引入sealed class Result
来封装行为,并使ViewModel
更具可读性。
class TestViewModel(val repo: Repo): ViewModel() {
private var askJob: Job? = null
fun load(query: String) {
askJob?.cancel()
askJob = viewModelScope.launch {
when (repo.getStuff()) {
is Result.Success -> TODO()
is Result.Failure -> TODO()
}
}
}
}
class Repo(private val api: Api) {
suspend fun getStuff() : Result {
return try {
Result.Success(api.getVeryImportantStuff())
} catch (e: java.lang.Exception) {
Result.Failure(e)
}
}
}
sealed class Result {
data class Success<out T: Any>(val data: T) : Result()
data class Failure(val error: Throwable) : Result()
}
interface Api {
suspend fun getVeryImportantStuff() : String
}
使用这种抽象级别,您的ViewModelTest
仅检查两种情况下发生的情况。
希望有帮助!