为了实现在每次修改后自动测试所有接口的需求,你可以使用Spring Boot Test框架结合JUnit 5编写集成测试。以下是完整的实现方案:
pom.xml
)<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiterartifactId>
<scope>testscope>
dependency>
dependencies>
TestConfig.java
)import org.springframework.http.HttpMethod;
import java.util.HashMap;
import java.util.Map;
public class TestConfig {
public static class ApiTestCase {
private final String url;
private final HttpMethod method;
private final Object requestBody;
private final int expectedStatus;
public ApiTestCase(String url, HttpMethod method, Object requestBody, int expectedStatus) {
this.url = url;
this.method = method;
this.requestBody = requestBody;
this.expectedStatus = expectedStatus;
}
// Getters
public String getUrl() { return url; }
public HttpMethod getMethod() { return method; }
public Object getRequestBody() { return requestBody; }
public int getExpectedStatus() { return expectedStatus; }
}
// 集中管理所有接口测试用例
public static Map<String, ApiTestCase> testCases() {
Map<String, ApiTestCase> cases = new HashMap<>();
// GET 请求示例
cases.put("用户列表接口", new ApiTestCase(
"/api/users",
HttpMethod.GET,
null,
200
));
// POST 请求示例
cases.put("创建用户接口", new ApiTestCase(
"/api/users",
HttpMethod.POST,
Map.of("name", "testUser", "email", "[email protected]"),
201
));
// PUT 请求示例
cases.put("更新用户接口", new ApiTestCase(
"/api/users/1",
HttpMethod.PUT,
Map.of("name", "updatedUser"),
200
));
// 添加更多测试用例...
// cases.put("其他接口", new ApiTestCase(...));
return cases;
}
}
ApiIntegrationTest.java
)import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.*;
import org.springframework.test.context.ActiveProfiles;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.fail;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class ApiIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testAllEndpoints() {
Map<String, TestConfig.ApiTestCase> testCases = TestConfig.testCases();
int total = testCases.size();
int passed = 0;
int failed = 0;
System.out.println("\n========== 开始接口测试 ==========");
System.out.println("待测试接口数量: " + total);
for (Map.Entry<String, TestConfig.ApiTestCase> entry : testCases.entrySet()) {
String caseName = entry.getKey();
TestConfig.ApiTestCase testCase = entry.getValue();
try {
ResponseEntity<String> response = executeRequest(testCase);
validateResponse(caseName, testCase, response);
passed++;
System.out.printf("✅ [成功] %-30s | 状态码: %d%n", caseName, response.getStatusCodeValue());
} catch (AssertionError e) {
failed++;
System.err.printf("❌ [失败] %-30s | 原因: %s%n", caseName, e.getMessage());
}
}
System.out.println("\n========== 测试结果 ==========");
System.out.println("总测试接口: " + total);
System.out.println("通过数量: " + passed);
System.out.println("失败数量: " + failed);
if (failed > 0) {
fail("有 " + failed + " 个接口测试未通过,请检查日志");
}
}
private ResponseEntity<String> executeRequest(TestConfig.ApiTestCase testCase) {
String url = "http://localhost:" + port + testCase.getUrl();
HttpMethod method = testCase.getMethod();
HttpEntity<Object> entity = new HttpEntity<>(testCase.getRequestBody(), createHeaders());
return restTemplate.exchange(url, method, entity, String.class);
}
private HttpHeaders createHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 如果需要认证,可添加token
// headers.setBearerAuth("your_token");
return headers;
}
private void validateResponse(String caseName,
TestConfig.ApiTestCase testCase,
ResponseEntity<String> response) {
// 验证状态码
if (response.getStatusCodeValue() != testCase.getExpectedStatus()) {
throw new AssertionError(
String.format("预期状态码: %d, 实际状态码: %d | 响应体: %s",
testCase.getExpectedStatus(),
response.getStatusCodeValue(),
response.getBody()
)
);
}
// 这里可以添加更多验证逻辑,例如:
// 1. 验证响应体结构
// 2. 验证关键字段值
// 3. 验证响应头信息
//
// 示例:
// if (!response.getBody().contains("expectedField")) {
// throw new AssertionError("响应中缺少关键字段: expectedField");
// }
}
}
配置测试用例:
TestConfig.testCases()
方法中添加/修改需要测试的接口url
: 接口路径method
: HTTP方法requestBody
: 请求体(GET可为null)expectedStatus
: 预期HTTP状态码运行测试:
ApiIntegrationTest
测试类mvn test
查看结果:
@Autowired
private UserRepository userRepository;
@Test
@Transactional
public void testCreateUser() {
// 测试前数据库状态
long initialCount = userRepository.count();
// 执行创建请求...
// 验证数据库变化
assertEquals(initialCount + 1, userRepository.count());
}
@ParameterizedTest
@MethodSource("provideUserIds")
void testGetUserById(Long userId) {
ResponseEntity<User> response = restTemplate.getForEntity(
"/api/users/" + userId, User.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
private static Stream<Arguments> provideUserIds() {
return Stream.of(
Arguments.of(1L),
Arguments.of(2L),
Arguments.of(3L)
);
}
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>3.0.0-M5version>
<configuration>
<reportName>ApiTestReportreportName>
configuration>
plugin>
运行: mvn test surefire-report:report
测试数据管理:
@Sql
注解初始化测试数据@Test
@Sql(scripts = "/test-data.sql")
public void testWithData() { ... }
环境隔离:
application-test.yml
配置文件认证处理:
createHeaders()
中添加认证token@WithMockUser
模拟认证用户测试分类:
@Tag("slow")
@Test
public void longRunningTest() { ... }
CI/CD集成:
# GitHub Actions 示例
- name: Run API Tests
run: mvn test
这个方案提供了:
- 集中式接口管理
- 自动遍历测试
- 详细错误报告
- 易于扩展的验证逻辑
- 清晰的测试结果输出
每次代码修改后,只需运行此测试套件,即可快速验证所有核心接口是否正常工作,显著提高发布效率。