如何在改造调用中抛出异常 [英] how to throw an exception on a retrofit call

查看:44
本文介绍了如何在改造调用中抛出异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

数据仓库

class DataRepository @Inject 构造函数(私有 val apiServiceInterface: ApiServiceInterface){暂停乐趣 getCreditReport(): CreditReportResponse {尝试 {val creditReport = apiServiceInterface.getDataFromApi()//这应该返回一个异常,我想抓住那个返回 CreditReportResponse(creditReport, CreditReportResponse.Status.SUCCESS)} catch (e: 异常) {返回 CreditReportResponse(null, CreditReportResponse.Status.FAILURE)}}}

API 服务接口

interface ApiServiceInterface {@GET("endpoint.json")暂停乐趣 getDataFromApi(): CreditReport}

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

 @Test有趣的 getCreditReportThrowException() {运行阻塞{val 响应 = dataRepository.getCreditReport()验证(apiServiceInterface,次(1)).getDataFromApi()Assert.assertEquals(CreditReportResponse.Status.FAILURE, response.status)}}

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

请推荐

谢谢R

解决方案

实际上@Vaibhav Goyal 提供了一个很好的建议,使您的测试更容易.假设您使用的是 MVVM 结构,在您的测试用例中,您可以注入一个模拟"对象.service 类来模拟你在测试用例中定义的行为,所以图会是这样的

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

@Test有趣的 test_exception() {//给定val mockService = mockk()val 存储库 = DataRepository(mockService)每个 { mockService.getDataFromApi() } 都会抛出 Exception("Error")//什么时候val 响应 = runBlocking {repository.getCreditReport()}//然后验证(完全 = 1){ mockService.getDataFromApi }assertEquals(CreditReportResponse.Status.FAILURE,response.status)}

但是如果你想测试Retrofit抛出的异常,那么你可能需要square的mockServer库来帮助你实现这个

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

@Test有趣的 test_exception_from_retrofit() {//可以放在setup方法/junit4规则或junit5类中val mockWebServer = MockWebServer()mockWebServer.start()//给定val service = Retrofit.Builder().baseUrl(mockWebServer.url("/").toString()).建造().create(ApiServiceInterface::class)val 存储库 = 数据存储库(服务)//什么时候mockWebServer.enqueue(MockResponse().setResponseCode(500).setBody("""{"name":"Tony}""")//可以读取json文件内容然后放这里)val 响应 = runBlocking {repository.getCreditReport()}//然后验证(完全 = 1){ mockService.getDataFromApi }assertEquals(CreditReportResponse.Status.FAILURE,response.status)//可以放入tearDown/在junit4 规则或juni5 类中mockWebServer.shutdown()}

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

加分点

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

I am making an api call using retrofit and I want to write a unit test to check if it returns an exception.

I want to force the retrofit call to return an exception

DataRepository

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)
        }
    }
}

ApiServiceInterface

interface ApiServiceInterface {

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

I have written a test case for getCreditReport which should validate the failure scenario

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

so to make the above test case pass, I need to force the network call to throw and exception

please suggest

Thanks R

解决方案

Actually @Vaibhav Goyal provided a good suggestion to make your testing as easier. Assuming you are using MVVM structure, in your test cases you can inject a "mock" service class to mock the behaviours that you defined in the test cases, so the graph will be like this

Since I am using mockk library at the moment, the actual implementation in your code base would be a little bit different.

@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)
}

But if you want to test the exception thrown from Retrofit, then you might need mockServer library from square to help you to achieve this https://github.com/square/okhttp#mockwebserver

And the graph for this would be like this

You also have to setup the mock server to do so

@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()
}

SO you can test different exception like json format invalid, 500 status code,data parsing exception

Bonus point

Usually I would put the testing json under test directory and make it almost same as the api path for better maintainence

这篇关于如何在改造调用中抛出异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆