1. 概述
本教程将聚焦于如何通过集成测试来验证 REST API 的行为与正确性。我们将发送真实的 HTTP 请求并解析 JSON 响应,从而确保 API 在实际使用场景下表现符合预期。
2. API 集成测试
API 集成测试关注的是我们的应用与外部依赖(如数据库、第三方服务或其他 API)之间的交互。✅ 它的目标是验证系统中各个组件是否能协同工作。
与单元测试不同,集成测试不是孤立地测试单个类或方法,而是模拟真实请求流程,检查 API 的输入输出是否符合预期。
2.1. 为什么需要 API 集成测试
虽然单元测试能保证代码模块本身没问题,但无法发现模块之间协作时的潜在问题。⚠️ 集成测试正好补上了这一环,它验证了模块间通信是否顺畅,避免出现“各自安好,合体翻车”的尴尬。
此外,它还能增强团队对上线系统的信心,减少部署后的故障风险。
2.2. 何时进行 API 集成测试
一般来说,集成测试是在单元测试之后、正式发布之前进行的。当单元测试确认各个模块工作正常后,集成测试就负责检查这些模块是否能“和睦相处”。
特别是在引入新功能或更新时,集成测试是防止回归问题的重要防线。
3. 测试状态码
为了验证 API 在用户不存在时的响应是否正确,我们可以测试返回的状态码:
@Test
public void givenUserDoesNotExists_whenUserInfoIsRetrieved_then404IsReceived()
throws ClientProtocolException, IOException {
// Given
String name = RandomStringUtils.randomAlphabetic( 8 );
HttpUriRequest request = new HttpGet( "https://api.github.com/users/" + name );
// When
HttpResponse httpResponse = HttpClientBuilder.create().build().execute( request );
// Then
assertThat(
httpResponse.getStatusLine().getStatusCode(),
equalTo(HttpStatus.SC_NOT_FOUND));
}
✅ 这是一个基础但非常关键的测试,确保最基本的“失败路径”能被正确处理。如果这个测试失败,那说明 API 的基本行为已经出问题,其他测试也失去了意义。
4. 测试媒体类型
我们还可以验证响应的 Content-Type
是否为 JSON,以确保返回的是结构化数据:
@Test
public void
givenRequestWithNoAcceptHeader_whenRequestIsExecuted_thenDefaultResponseContentTypeIsJson()
throws ClientProtocolException, IOException {
// Given
String jsonMimeType = "application/json";
HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" );
// When
HttpResponse response = HttpClientBuilder.create().build().execute( request );
// Then
String mimeType = ContentType.getOrDefault(response.getEntity()).getMimeType();
assertEquals( jsonMimeType, mimeType );
}
⚠️ 确保响应是 JSON 格式,这是后续解析 payload 的前提。逻辑上我们是逐步验证:先看状态码,再看媒体类型,最后才解析内容。
5. 测试 JSON 响应体
为了验证 API 是否返回了正确的数据,我们可以解析响应体中的 JSON 内容并做断言:
@Test
public void
givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect()
throws ClientProtocolException, IOException {
// Given
HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" );
// When
HttpResponse response = HttpClientBuilder.create().build().execute( request );
// Then
GitHubUser resource = RetrieveUtil.retrieveResourceFromResponse(
response, GitHubUser.class);
assertThat( "eugenp", Matchers.is( resource.getLogin() ) );
}
💡 注意:虽然 GitHub 默认返回的是 JSON,但在实际项目中,我们通常会同时检查请求头中的 Accept
和响应头中的 Content-Type
,确保客户端和服务端在“说同一种语言”。
6. 测试辅助工具
我们使用 Jackson 2 来将原始 JSON 字符串反序列化为类型安全的 Java 对象:
public class GitHubUser {
private String login;
// standard getters and setters
}
为了保持测试代码的简洁与可读性,我们使用一个简单的工具方法:
public static <T> T retrieveResourceFromResponse(HttpResponse response, Class<T> clazz)
throws IOException {
String jsonFromResponse = EntityUtils.toString(response.getEntity());
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper.readValue(jsonFromResponse, clazz);
}
📌 注意:这里我们配置了 Jackson 忽略未知字段,因为在对接 GitHub API 时它返回的字段较多,我们只关心必要的字段。
7. 依赖项
以下是我们测试中用到的库,均可在 Maven Central 找到:
8. 总结
本文只是完整集成测试体系中的一部分,主要关注 REST API 的基本功能验证。✅ 我们没有涉及更复杂的场景,例如:
❌ API 的可发现性
❌ 同一资源的多种表示方式(Content Negotiation)等
后续可以根据项目需求,逐步补充这些测试维度。