【问题标题】:how to throw an exception on a retrofit call如何在改造调用中引发异常
【发布时间】:2021-10-21 15:06:44
【问题描述】:

我正在使用改造进行 api 调用,我想编写一个单元测试来检查它是否返回异常。

我想强制改造调用返回异常

数据存储库

class DataRepository @Inject constructor(
        private val apiServiceInterface: ApiServiceInterface
) {

    suspend fun getCreditReport(): CreditReportResponse {
        try {
            val creditReport = apiServiceInterface.getDataFromApi() // THIS SHOULD RETURN AN EXCEPTION AND I WANT TO CATCH THAT
            return CreditReportResponse(creditReport, CreditReportResponse.Status.SUCCESS)
        } catch (e: Exception) {
            return CreditReportResponse(null, CreditReportResponse.Status.FAILURE)
        }
    }
}

ApiService接口

interface ApiServiceInterface {

    @GET("endpoint.json")
    suspend fun getDataFromApi(): CreditReport
}

我已经为 getCreditReport 编写了一个测试用例,它应该验证失败场景

  @Test
    fun getCreditReportThrowException() {
        runBlocking {
            val response = dataRepository.getCreditReport()
            verify(apiServiceInterface, times(1)).getDataFromApi()
            Assert.assertEquals(CreditReportResponse.Status.FAILURE, response.status)
        }
    }

所以要让上面的测试用例通过,我需要强制网络调用抛出异常

请推荐

谢谢 回复

【问题讨论】:

  • 您可以通过在 GET 方法中提供错误的路由来做到这一点,但是有一种更好的方法来测试存储库,方法是创建存储库一个接口,然后每当您想测试存储库时,您可以通过 FakeRepository 实现,它会让测试更容易。
  • 你能分享一个例子吗

标签: android unit-testing kotlin retrofit


【解决方案1】:

实际上@Vaibhav Goyal 提供了一个很好的建议,让您的测试更容易。假设您使用的是 MVVM 结构,在您的测试用例中,您可以注入一个“模拟”服务类来模拟您在测试用例中定义的行为,因此图表将是这样的

由于我目前使用的是 mockk 库,因此您的代码库中的实际实现会有些不同。

@Test
fun test_exception() {
    // given
    val mockService = mockk<ApiServiceInterface>()
    val repository = DataRepository(mockService)
    every { mockService.getDataFromApi() } throws Exception("Error")

    // when
    val response = runBlocking {
        repository.getCreditReport()
    }

    // then
    verify(exactly = 1) { mockService.getDataFromApi }
    assertEquals(CreditReportResponse.Status.FAILURE,response.status)
}

但是如果你想测试 Retrofit 抛出的异常,那么你可能需要 square 的 mockServer 库来帮助你实现这个https://github.com/square/okhttp#mockwebserver

这个图表会是这样的

您还必须设置模拟服务器才能这样做

@Test
fun test_exception_from_retrofit() {
    // can put in the setup method / in junit4 rule or junit5 class 
    val  mockWebServer = MockWebServer()
    mockWebServer.start()
    
    // given
    val service = Retrofit.Builder()
        .baseUrl(mockWebServer.url("/").toString())
        .build()
        .create(ApiServiceInterface::class)
    val repository = DataRepository(service)

    // when
    mockWebServer.enqueue(MockResponse()
        .setResponseCode(500)
        .setBody("""{"name":"Tony}""") // you can read the json file content and then put it here
    )
    val response = runBlocking {
        repository.getCreditReport()
    }

    // then
    verify(exactly = 1) { mockService.getDataFromApi }
    assertEquals(CreditReportResponse.Status.FAILURE,response.status)
    
    // can put in tearDown / in junit4 rule or juni5 class
    mockWebServer.shutdown()
}

所以你可以测试不同的异常,比如json格式无效、500状态码、数据解析异常

奖励积分

通常我会将测试json放在test目录下,并使其与api路径几乎相同,以便更好地维护

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 2019-07-09
    • 2018-11-11
    相关资源
    最近更新 更多