模拟改型暂停函数无限响应

问题描述 投票:0回答:1

我想测试服务器不返回响应的情况,然后我们触发下一个网络调用(例如搜索查询)。

所以我们基本上在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

unit-testing mockito kotlin-coroutines android-viewmodel
1个回答
0
投票

看起来您想在服务器超时或类似情况发生时测试方案。

在这种情况下,您可以在进行模拟时说,首先尝试它返回对象,然后在第二次执行时抛出诸如java.net.ConnectException: Connection timed out之类的异常。

                whenever(mockApi.getVeryImportantStuff())
                .thenReturn(someObjet)
                .thenThrow(ConnectException("timed out"))

并且这应该可行,但是您必须在ViewModel中进行try / catch块,这并不理想。我建议您添加其他抽象。

您可以选择RepositoryUseCase,还是您想在其中移动网络呼叫的任何模式/名称。然后引入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仅检查两种情况下发生的情况。

希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.