如何用MockWebServer仅测试Retrofit请求参数而不执行请求?
解决方案
当然可以!这里有几个不同的方案,你可以根据自己的测试场景选择:
1. 返回最小合法的JSON响应(最简单的方案)
Retrofit需要能把响应解析成TimeResponse对象,但你完全不需要返回真实的大数据——只需要返回满足对象结构的最小合法JSON即可。比如假设你的TimeResponse是这样定义的:
data class TimeResponse( val iso: String, val epoch: Double )
那你只需要返回包含必填字段的极简JSON,比如:
{"iso": "dummy", "epoch": 0.0}
这样既满足了解析要求,又不用处理庞大的真实数据,同时你可以专注于验证请求的路径、请求头等信息。修改后的测试代码如下:
@Test fun validate_time_request() = runBlocking { // 用极简JSON代替真实大数据 val minimalValidResponse = """{"iso": "dummy", "epoch": 0.0}""" mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(minimalValidResponse)) // 仍然需要调用API触发请求,但响应是极简的,解析成本极低 createClient().time() // 重点验证请求负载 val recordedRequest = mockWebServer.takeRequest() assertThat(recordedRequest.path).isEqualTo("/time/") assertThat(recordedRequest.method).isEqualTo("GET") // 如果有请求头需要验证,比如Authorization、Accept等 // assertThat(recordedRequest.getHeader("Accept")).isEqualTo("application/json") }
2. 自定义Converter跳过响应解析(适合完全不想写JSON的场景)
如果你连极简JSON都不想写,可以自定义一个Retrofit的Converter,让它在解析特定接口的响应时直接返回一个默认的TimeResponse实例,这样MockWebServer可以返回任意内容(甚至空响应)。
首先创建一个包装原Converter的自定义Converter:
class SkipTimeResponseConverter( private val delegate: Converter<ResponseBody, TimeResponse> ) : Converter<ResponseBody, TimeResponse> { override fun convert(value: ResponseBody): TimeResponse { // 直接返回默认实例,跳过真实解析 return TimeResponse(iso = "dummy", epoch = 0.0) } }
然后在创建Retrofit客户端时替换对应的Converter:
private fun createClient(): AppApi { val gson = Gson() val retrofitBuilder = Retrofit.Builder() .baseUrl(mockWebServer.url("/").toString()) .addConverterFactory(object : Converter.Factory() { override fun responseBodyConverter( type: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): Converter<ResponseBody, *>? { // 只对TimeResponse类型的响应使用自定义Converter return if (type == TimeResponse::class.java) { val originalConverter = GsonConverterFactory.create(gson) .responseBodyConverter(type, annotations, retrofit) as Converter<ResponseBody, TimeResponse> SkipTimeResponseConverter(originalConverter) } else { // 其他类型用原Converter super.responseBodyConverter(type, annotations, retrofit) } } }) return retrofitBuilder.build().create(AppApi::class.java) }
现在测试时MockWebServer可以直接返回空响应:
@Test fun validate_time_request_with_empty_response() = runBlocking { mockWebServer.enqueue(MockResponse().setResponseCode(200)) // 空响应也能正常解析 createClient().time() val recordedRequest = mockWebServer.takeRequest() assertThat(recordedRequest.path).isEqualTo("/time/") // 其他请求验证逻辑 }
3. 直接验证Retrofit构建的请求(无需发送请求)
如果你根本不需要发送请求,只是想验证Retrofit根据接口注解构建的请求是否正确,可以把接口改成返回Call<TimeResponse>,然后直接获取请求对象进行验证,完全不需要MockWebServer:
// 修改接口定义 interface AppApi { @GET("/time/") fun time(): Call<TimeResponse> } // 测试代码 @Test fun verify_request_build_logic() { val call = createClient().time() val request = call.request() assertThat(request.url().encodedPath()).isEqualTo("/time/") assertThat(request.method()).isEqualTo("GET") // 验证请求头 assertThat(request.header("Accept")).isEqualTo("application/json") }
这种方法适合仅验证接口注解(比如路径、HTTP方法、请求头)的场景,不需要涉及任何网络请求模拟。
内容的提问来源于stack exchange,提问作者anticafe
相关产品推荐
相关产品推荐

