mcpField
S
spring-boot-test-patterns

spring-boot-test-patterns

github.com/giuseppe-trisciuoglio测试与质量3654.3k 次安装7 周前更新
代码仓库

关于 spring-boot-test-patterns

为 Spring Boot 开发者提供测试模式指南,涵盖 Mockito、JUnit 5 和 Testcontainers。按单元、切片与集成测试分层,帮助选择测试范围并控制上下文开销。

主要功能

  1. 01单元测试与 Mockito 模式
  2. 02按层使用 Spring 测试切片
  3. 03MockMvc REST API 测试
  4. 04Testcontainers 与服务连接
  5. 05依赖配置及 CI/CD 指南

适用场景

  1. 01为服务或仓储编写隔离测试
  2. 02使用真实数据库运行集成测试
  3. 03验证 REST 控制器与 API
  4. 04配置自动化测试流水线

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill spring-boot-test-patterns

安装后在 Claude Code 中输入/spring-boot-test-patterns确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api-reference.md
best-practices.md
ci-cd-configuration.md
slice-testing.md
test-dependencies.md
testcontainers-setup.md
unit-testing.md
workflow-patterns.md

详细介绍

Spring Boot 测试模式

概述

全面介绍如何使用 JUnit 5、Mockito、Testcontainers 和经过性能优化的切片测试模式,为 Spring Boot 应用编写健壮的测试套件。

适用场景

  • 为具有模拟依赖项的服务或仓库编写单元测试
  • 使用 Testcontainers 通过真实数据库实现集成测试
  • 使用 @WebMvcTest 或 MockMvc 测试 REST API
  • 在 Spring Boot 3.5+ 中配置 @ServiceConnection 来管理容器

快速参考

测试类型注解目标耗时用例
单元测试@ExtendWith(MockitoExtension.class)< 50ms不加载 Spring 上下文的业务逻辑测试
仓库测试@DataJpaTest< 100ms在最小上下文中测试数据库操作
控制器测试@WebMvcTest / @WebFluxTest< 100msREST API 层测试
集成测试@SpringBootTest< 500ms使用容器加载完整应用上下文
Testcontainers@ServiceConnection / @Testcontainers不定真实数据库/消息代理容器

核心概念

测试架构理念
  1. 单元测试 — 快速、隔离,不加载 Spring 上下文(< 50ms)
  2. 切片测试 — 为特定层加载最小 Spring 上下文(< 100ms)
  3. 集成测试 — 使用真实依赖项加载完整 Spring 上下文(< 500ms)
关键注解

Spring Boot 测试:

  • @SpringBootTest — 完整应用上下文(谨慎使用)
  • @DataJpaTest — 仅测试 JPA 组件(仓库、实体)
  • @WebMvcTest — 仅测试 MVC 层(控制器、@ControllerAdvice)
  • @WebFluxTest — 仅测试 WebFlux 层(响应式控制器)
  • @JsonTest — 仅测试 JSON 序列化组件

Testcontainers:

  • @ServiceConnection — 将 Testcontainer 接入 Spring Boot(3.5+)
  • @DynamicPropertySource — 在运行时注册动态属性
  • @Testcontainers — 启用 Testcontainers 生命周期管理

操作指南

1. 单元测试模式

使用模拟依赖项测试业务逻辑:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldFindUserByIdWhenExists() {
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        Optional<User> result = userService.findById(1L);
        assertThat(result).isPresent();
        verify(userRepository).findById(1L);
    }
}

高级模式请参阅 unit-testing.md。

2. 切片测试模式

使用针对特定层的测试切片:

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestContainerConfig
class UserRepositoryIntegrationTest {
    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldSaveAndRetrieveUser() {
        User saved = userRepository.save(user);
        assertThat(userRepository.findByEmail("[email protected]")).isPresent();
    }
}

所有切片模式请参阅 slice-testing.md。

3. REST API 测试模式

使用 MockMvc 测试控制器:

@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void shouldGetUserById() throws Exception {
        mockMvc.perform(get("/api/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.email").value("[email protected]"));
    }
}
4. 使用 @ServiceConnection 配置 Testcontainers

在 Spring Boot 3.5+ 中配置容器:

@TestConfiguration
public class TestContainerConfig {
    @Bean
    @ServiceConnection
    public PostgreSQLContainer<?> postgresContainer() {
        return new PostgreSQLContainer<>("postgres:16-alpine");
    }
}

在测试类上使用 @Import(TestContainerConfig.class)。 详细配置请参阅 testcontainers-setup.md。

5. 添加依赖项

添加所需的测试依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.19.0</version>
    <scope>test</scope>
</dependency>

完整依赖项列表请参阅 test-dependencies.md。

6. 配置 CI/CD

设置 GitHub Actions 以自动运行测试:

name: Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      docker:
        image: docker:20-dind
    steps:
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        distribution: 'temurin'
    - name: Run tests
      run: ./mvnw test

完整的 CI/CD 模式请参阅 ci-cd-configuration.md。

验证检查点

实现测试后,请验证:

  • 容器正在运行:docker ps(查找 testcontainer 镜像)
  • 上下文已加载:检查启动日志中的 "Started Application in X.XX seconds"
  • 测试隔离性:单独运行测试,并确认没有相互污染

示例

使用 @ServiceConnection 的完整集成测试
@SpringBootTest
@Import(TestContainerConfig.class)
class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldCreateOrderForExistingUser() {
        User user = userRepository.save(User.builder()
            .email("[email protected]")
            .build());

        Order order = orderService.createOrder(user.getId(), List.of(
            new OrderItem("SKU-001", 2)
        ));

        assertThat(order.getId()).isNotNull();
        assertThat(order.getStatus()).isEqualTo(OrderStatus.PENDING);
    }
}
使用真实数据库的 @DataJpaTest
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestContainerConfig
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldFindByEmail() {
        userRepository.save(User.builder()
            .email("[email protected]")
            .build());
        assertThat(userRepository.findByEmail("[email protected]"))
            .isPresent();
    }
}

完整的端到端示例请参阅 workflow-patterns.md。

最佳实践

  • 使用合适的测试类型:仓库使用 @DataJpaTest,控制器使用 @WebMvcTest,仅在完整集成测试中使用 @SpringBootTest
  • 在 Spring Boot 3.5+ 中优先使用 @ServiceConnection,相比 @DynamicPropertySource,它能更简洁地管理容器
  • 确保测试具有确定性:在 @BeforeEach 中显式初始化所有测试数据
  • 按层组织测试:按层分组测试,以最大限度地利用上下文缓存
  • 在 JVM 级别复用 Testcontainers(withReuse(true) + TESTCONTAINERS_REUSE_ENABLE=true)
  • 避免使用 @DirtiesContext:它会强制重建上下文,显著降低性能
  • 模拟外部服务,仅在必要时使用真实数据库
  • 性能目标:单元测试 < 50ms,切片测试 < 100ms,集成测试 < 500ms

限制和警告

  • 除非绝对必要,否则切勿使用 @DirtiesContext(它会强制重建上下文)
  • 避免混用不同配置的 @MockBean(会创建独立的上下文)
  • Testcontainers 需要 Docker;确保 CI/CD 流水线支持 Docker
  • 不要依赖测试执行顺序;每个测试都必须相互独立
  • 谨慎使用 @TestPropertySource(会创建独立的上下文)
  • 不要在单元测试中使用 @SpringBootTest;请改用纯 Mockito
  • 不同的 @MockBean 配置可能会使上下文缓存失效
  • 避免在测试中使用静态可变状态(会导致测试结果不稳定)

参考资料

评论

支持 Markdown