如何在改造调用中抛出异常 [英] how to throw an exception on a retrofit call
问题描述
我正在使用改造进行 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屋!