第 4 章:测试
本章系统梳理了 Spring Boot 云原生应用的测试体系,涵盖单元测试、集成测试、Mock 技术、测试切片、端到端测试及消费者驱动契约测试等关键实践,帮助开发者构建高质量、可持续交付的微服务系统。
测试的构成
在云原生开发中,测试分为单元测试和集成测试。单元测试关注单个组件的功能,集成测试则验证多个组件或服务间的协作。建议将所有测试代码放在 src/test/{java, resources}
目录,确保每次构建或提交前自动运行所有测试用例。
在 Spring Boot 中进行测试
Spring Boot 支持两类测试:
- 单元测试:不依赖 Spring 上下文,适合纯 Java 逻辑。
- 集成测试:依赖 Spring ApplicationContext,验证组件集成。
通过在 pom.xml
添加 spring-boot-starter-test
依赖,即可获得完整的测试支持。Spring Initializr 生成的项目已默认集成。
基本集成测试示例
@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplicationContextTests {
@Autowired
private ApplicationContext applicationContext;
@Test
public void contextLoads() {
Assert.assertNotNull(this.applicationContext);
}
}
@SpringBootTest
自动加载应用上下文,@RunWith(SpringRunner.class)
启用 Spring 测试环境。
Spring Boot 测试目录结构
典型项目结构如下:
- mvnw
- mvnw.cmd
- pom.xml
- src/
- main/
- java/com/example/Application.java
- resources/application.properties
- test/
- java/com/example/ApplicationTests.java
主代码和测试代码包结构应一致,便于自动扫描和加载。
集成测试与 Mock 技术
集成测试关注组件协作,常用 Mock 技术隔离外部依赖。Spring Boot 支持 @MockBean
注解,将指定 bean 替换为 Mockito mock 对象,便于模拟外部服务或数据库。
Mock 示例(伪代码)
@RunWith(SpringRunner.class)
public class AccountServiceTests {
@MockBean
private UserService userService;
@MockBean
private AccountRepository accountRepository;
@Before
public void before() {
accountService = new AccountService(accountRepository, userService);
}
@Test
public void getUserAccountsReturnsSingleAccount() {
// given: 模拟 repository 和 userService 的行为
// when: 调用 accountService.getUserAccounts()
// then: 断言返回结果
}
}
推荐使用构造函数注入,便于测试时替换依赖。
测试切片与自动化注解
Spring Boot 1.4+ 支持测试切片(Test Slice),可只加载部分自动配置,提升测试效率。常用注解包括:
@JsonTest
:仅测试 JSON 序列化/反序列化@WebMvcTest
:仅测试 MVC 控制器@DataJpaTest
:仅测试 JPA repository,自动配置内存数据库@RestClientTest
:仅测试 RestTemplate 与远程服务交互
@JsonTest 示例
@RunWith(SpringRunner.class)
@JsonTest
public class UserTests {
@Autowired
private JacksonTester<User> json;
@Test
public void serializeJson() {
// 断言序列化结果与预期一致
}
}
@WebMvcTest 示例
@RunWith(SpringRunner.class)
@WebMvcTest(AccountController.class)
public class AccountControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private AccountService accountService;
@Test
public void getUserAccountsShouldReturnAccounts() throws Exception {
// given: 模拟 accountService 行为
// when: mvc.perform(get("/v1/accounts"))
// then: 断言 HTTP 响应
}
}
@DataJpaTest 示例
@RunWith(SpringRunner.class)
@DataJpaTest
public class AccountRepositoryTest {
@Autowired
private AccountRepository accountRepository;
@Autowired
private TestEntityManager entityManager;
@Test
public void findUserAccountsShouldReturnAccounts() {
// 使用 entityManager 持久化实体
// 断言 repository 查询结果
}
}
@RestClientTest 示例
@RunWith(SpringRunner.class)
@RestClientTest(UserService.class)
public class UserServiceTests {
@Autowired
private UserService userService;
@Autowired
private MockRestServiceServer server;
@Test
public void getAuthenticationUserShouldReturnUser() {
// server.expect(...).andRespond(...)
// 断言 userService.getAuthenticationUser() 返回结果
}
}
端到端测试与分布式系统一致性
端到端测试(E2E)验证分布式系统的业务流程和用户体验,确保多个微服务协作无误。分布式状态一致性是核心挑战,需关注最终一致性和状态同步。
first_name | last_name | status | |
---|---|---|---|
Bob | Dylan | [email protected] | PENDING |
Taylor | Swift | [email protected] | CONFIRMED |
Tracy | Chapman | [email protected] | ARCHIVED |
Bruno | Mars | [email protected] | INACTIVE |
状态字段影响业务流程,不同状态下系统行为不同。分布式环境下需设计合理的测试用例,确保状态最终一致。
消费者驱动契约测试(CDC-T)
CDC-T 通过契约文件描述服务间交互,生产者发布存根(stub),消费者在集成测试中使用存根模拟远程服务。Spring Cloud Contract 提供 CDC-T 支持,自动生成和发布存根。
Spring Cloud Contract 流程简述
- 生产者定义契约(Groovy DSL),发布存根到仓库
- 消费者集成测试时通过 Stub Runner 加载存根,模拟远程服务
- 断言服务间交互符合契约
契约定义示例(伪代码)
org.springframework.cloud.contract.spec.Contract.make {
request {
method 'GET'
url '/uaa/v1/me'
headers { header('Content-Type': consumer(regex('application/*json*'))) }
}
response {
status 200
body([
username: value(producer(regex('[A-Za-z0-9]+'))),
// ... 其他字段
])
headers { header('Content-Type': value('application/json; charset=UTF-8')) }
}
}
消费者测试集成存根示例
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"group:user-microservice:stubs:8081"}, workOffline = true)
public class ConsumerDrivenTests {
@Autowired
private UserService service;
@Test
public void shouldReturnAuthenticatedUser() {
// 调用 service.getAuthenticatedUser(),断言结果符合契约
}
}
总结
本章系统梳理了 Spring Boot 测试体系,包括单元测试、集成测试、Mock 技术、测试切片、端到端测试和消费者驱动契约测试。通过合理设计和自动化测试,开发者可持续保障微服务系统的质量和可交付性,为云原生架构下的持续交付和高效运维打下坚实基础。