如何为使用OkHttp调用第三方API的Java方法编写单元测试?
正确实现单元测试的步骤
1. 依赖准备
首先确保测试依赖引入完整,和你项目中OkHttp版本保持一致:
<!-- MockWebServer依赖 --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>mockwebserver</artifactId> <version>你的OkHttp版本号</version> <scope>test</scope> </dependency> <!-- 静态方法Mock依赖(可选,用来跳过QueryUtils、PartitionUtil的逻辑校验) --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency>
2. 完整测试实现
以下是基于JUnit5的标准测试代码:
import okhttp3.OkHttpClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import static org.mockito.Mockito.mockStatic; import static org.junit.jupiter.api.Assertions.*; // 假设你的业务方法放在AuditDataService类中 class AuditDataServiceTest { private MockWebServer mockServer; private OkHttpClient okHttpClient; private final AuditDataService auditDataService = new AuditDataService(); @BeforeEach void init() throws Exception { // 启动Mock服务 mockServer = new MockWebServer(); mockServer.start(); okHttpClient = new OkHttpClient(); } @AfterEach void close() throws Exception { // 关闭Mock服务释放端口 mockServer.shutdown(); } @Test void getAuditData_returnCorrectDataWhenRequestSuccess() throws IOException, InterruptedException { // 1. 构造符合GraphQL规范的响应体,必须包含data层级匹配你业务代码的提取规则 String mockResponseBody = """ { "data": { "auditData": [ {"id": 1001, "remark": "测试审计数据1", "operator": "admin"}, {"id": 1002, "remark": "测试审计数据2", "operator": "user"} ] } } """; // 2. 入队Mock响应 MockResponse mockResponse = new MockResponse() .setResponseCode(200) .addHeader("Content-Type", "application/json; charset=utf-8") .setBody(mockResponseBody); mockServer.enqueue(mockResponse); // 3. Mock静态工具类(如果不需要校验工具类逻辑可以这么写,要测试工具类则去掉该部分传真实参数即可) try (MockedStatic<QueryUtils> queryUtilsMock = mockStatic(QueryUtils.class); MockedStatic<PartitionUtil> partitionUtilMock = mockStatic(PartitionUtil.class)) { // 定义静态方法返回值 String mockGraphqlQuery = "query { auditData(id:1) { id remark } }"; queryUtilsMock.when(() -> QueryUtils.getAuditDataQuery(1, 86, 202401, 1, "read_partition_01")) .thenReturn(mockGraphqlQuery); partitionUtilMock.when(() -> PartitionUtil.getReadPartition("test_token_abc")) .thenReturn("read_partition_01"); // 4. 拿到Mock服务的地址,传入业务方法(这是大多数人测试失败的核心原因:之前传了真实第三方地址,请求没打到Mock服务上) String mockServerUrl = mockServer.url("/graphql").toString(); // 5. 调用待测试方法 List<AuditData> result = auditDataService.getAuditData( okHttpClient, 1, 86, 202401, 1, mockServerUrl, "test_token_abc" ); // 6. 校验返回结果 assertEquals(2, result.size()); assertEquals("admin", result.get(0).getOperator()); // 7. 可选:校验请求参数是否符合预期 RecordedRequest actualRequest = mockServer.takeRequest(); assertEquals("POST", actualRequest.getMethod()); assertEquals("Bearer test_token_abc", actualRequest.getHeader("Authorization")); assertTrue(actualRequest.getBody().readUtf8().contains(mockGraphqlQuery)); } } }
3. 常见失败原因排查
- 没有将
MockWebServer生成的动态地址传入业务方法,而是硬编码了真实第三方API地址 - 响应体格式不符合GraphQL规范,缺少
data层级导致extractValueAsObject提取结果为空 AuditData类没有无参构造、Getter/Setter方法,导致反序列化失败
内容的提问来源于stack exchange,提问作者Hola
相关产品推荐
相关产品推荐

