研发协作
Spring Boot 测试模式:为服务、仓库和 REST…
在 Spring Boot 应用中编写单元测试、@DataJpaTest/@WebMvcTest 切片测试、@SpringBootTest 集成测试和 Testcontainers 容器化测试时,用这些模式选对注解、避免上下文重建并控制测试耗时。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
Spring Boot 测试模式:为服务特定
解决思路
- 按测试架构选择类型:单元测试快速隔离且无 Spring 上下文(< 50ms);切片测试针对特定层使用最小 Spring 上下文(< 100ms);集成测试使用完整 Spring 上下文和真实依赖(< 500ms)。
- 按快速参考选择注解:单元测试用 @ExtendWith(MockitoExtension.class),目标 < 50ms,用于无 Spring 上下文的业务逻辑;仓库测试用 @DataJpaTest,目标 < 100ms,用于最小上下文的数据库操作;控制器测试用 @WebMvcTest 或 @WebFluxTest,目标 < 100ms,用于 REST API 层;集成测试用 @SpringBootTest,目标 < 500ms,用于带容器的完整应用上下文;Testcontainers 用 @ServiceConnection 或 @Testcontainers,用于真实数据库/消息代理容器。
- 使用 Spring Boot 测试注解:@SpringBootTest 加载完整应用上下文(谨慎使用);@DataJpaTest 只加载 JPA 组件(repositories、entities);@WebMvcTest 只加载 MVC 层(controllers、@ControllerAdvice);@WebFluxTest 只加载 WebFlux 层(reactive controllers);@JsonTest 只加载 JSON 序列化组件。
- 使用 Testcontainers 注解:@ServiceConnection 将 Testcontainer 接入 Spring Boot(3.5+);@DynamicPropertySource 在运行时注册动态属性;@Testcontainers 启用 Testcontainers 生命周期管理。
- 编写单元测试模式:在测试类上使用 @ExtendWith(MockitoExtension.class);用 @Mock 声明依赖;用 @InjectMocks 注入被测服务;用 when(...).thenReturn(...) 桩化依赖;用 assertThat(...) 断言结果;用 verify(...) 验证交互。参考 unit-testing.md。
- 编写切片测试模式:使用 @DataJpaTest;配合 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE);引入 @TestContainerConfig;@Autowired 注入 UserRepository;保存并查询实体进行断言。参考 slice-testing.md。
- 编写 REST API 测试模式:使用 @WebMvcTest(UserController.class);@Autowired 注入 MockMvc;用 @MockBean 模拟 UserService;用 mockMvc.perform(get('/api/users/1')) 发请求;用 .andExpect(status().isOk()) 和 .andExpect(jsonPath('$.email').value('test@example.com')) 断言。
- 配置 Testcontainers 与 @ServiceConnection:创建 @TestConfiguration 类 TestContainerConfig;定义 @Bean 和 @ServiceConnection 的 PostgreSQLContainer<>,镜像用 postgres:16-alpine;在测试类上用 @Import(TestContainerConfig.class) 引入。参考 testcontainers-setup.md。
- 添加测试依赖:在 Maven 中加入 org.springframework.boot:spring-boot-starter-test,scope 为 test;加入 org.testcontainers:junit-jupiter,version 为 1.19.0,scope 为 test。参考 test-dependencies.md。
- 配置 CI/CD:使用 GitHub Actions,触发条件为 on: [push, pull_request];jobs.test.runs-on 设为 ubuntu-latest;services.docker.image 设为 docker:20-dind;steps 使用 actions/checkout@v4、actions/setup-java@v4 且 distribution 为 'temurin';运行 ./mvnw test。参考 ci-cd-configuration.md。
- 验证检查点:测试后执行 docker ps,查找 testcontainer 镜像以确认容器运行。
- 验证检查点:检查启动日志中的 'Started Application in X.XX seconds' 以确认上下文加载。
- 验证检查点:单独运行每个测试,确认无交叉污染以验证测试隔离。
- 完整集成测试示例:使用 @SpringBootTest 和 @Import(TestContainerConfig.class);@Autowired 注入 OrderService、UserRepository;保存 User(email 为 order-test@example.com);调用 orderService.createOrder(user.getId(), List.of(new OrderItem('SKU-001', 2)));断言 order.getId() 非空且 order.getStatus() 等于 OrderStatus.PENDING。参考 workflow-patterns.md。
- @DataJpaTest 真实数据库示例:使用 @DataJpaTest、@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)、@TestContainerConfig;@Autowired 注入 UserRepository;保存 User(email 为 jpa-test@example.com);断言 userRepository.findByEmail('jpa-test@example.com') 存在。
- 最佳实践:使用正确的测试类型,仓库用 @DataJpaTest,控制器用 @WebMvcTest,只有完整集成才用 @SpringBootTest。
- 最佳实践:在 Spring Boot 3.5+ 优先用 @ServiceConnection 管理容器,替代 @DynamicPropertySource。
- 最佳实践:保持测试确定性,在 @BeforeEach 中显式初始化所有测试数据。
- 最佳实践:按层组织测试,将测试按层分组以最大化上下文缓存。
- 最佳实践:在 JVM 级别复用 Testcontainers,启用 withReuse(true) 并设置 TESTCONTAINERS_REUSE_ENABLE=true。
- 最佳实践:避免 @DirtiesContext,因为它会强制重建上下文并显著损害性能。
- 最佳实践:Mock 外部服务,仅在必要时使用真实数据库。
- 最佳实践:遵循性能目标:单元测试 < 50ms,切片测试 < 100ms,集成测试 < 500ms。
- 实施约束:除非绝对必要,否则不要使用 @DirtiesContext,因为它会强制上下文重建。
- 实施约束:避免混用不同配置的 @MockBean,否则会创建独立上下文。
- 实施约束:Testcontainers 需要 Docker,确保 CI/CD 流水线支持 Docker。
- 实施约束:不要依赖测试执行顺序,每个测试必须独立。
- 实施约束:谨慎使用 @TestPropertySource,因为它会创建独立上下文。
- 实施约束:不要用 @SpringBootTest 写单元测试,单元测试应使用普通 Mockito。
- 实施约束:不同 @MockBean 配置可能导致上下文缓存失效。
- 实施约束:避免在测试中使用静态可变状态,否则会导致测试不稳定。
- 参考文档:test-dependencies.md、unit-testing.md、slice-testing.md、testcontainers-setup.md、ci-cd-configuration.md、api-reference.md、best-practices.md、workflow-patterns.md。
适用边界 · 注意事项
- 不适用于非 Spring Boot 项目;该技能围绕 Spring Boot 测试注解和上下文。
- 当本地或 CI/CD 环境没有 Docker 时,不要使用依赖 Testcontainers 的测试模式。
- 如果只是写纯 Java 单元测试且不涉及 Spring 上下文,不需要本文的 Spring Boot 切片/集成测试模式,使用普通 JUnit + Mockito 即可。