首页 > 解决方案 > 如何在改造调用中引发异常

问题描述

我正在使用改造进行 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)
        }
    }

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

请建议

谢谢R

标签: androidunit-testingkotlinretrofit

解决方案


实际上@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路径几乎相同,以便更好地维护

在此处输入图像描述


推荐阅读