单元测试与集成测试

132 阅读3分钟

1. 核心测试框架:JUnit 与 Spring Test

  • JUnit:作为 Java 生态的标准测试框架,JUnit 5(结合 @Test 注解)用于定义测试用例。
  • Spring Test:提供与 Spring 上下文集成的支持,通过 @SpringBootTest 等注解加载 Spring 容器。
  • 扩展机制:JUnit 5 的 @ExtendWith(SpringExtension.class) 将 Spring 的依赖注入和生命周期管理集成到测试中。

2. 分层测试与测试切片(Test Slices)

Spring Boot 提供测试切片,仅加载与测试目标相关的组件,而非整个应用上下文,提升测试速度:

  • @WebMvcTest:仅加载 Web 层(Controller、Filter 等),自动配置 MockMvc 模拟 HTTP 请求。
  • @DataJpaTest:仅加载 JPA 组件,默认使用内存数据库(如 H2)测试 Repository 层。
  • @JsonTest:专注于 JSON 序列化/反序列化测试。
  • 其他切片:如 @RestClientTest(HTTP 客户端)、@JdbcTest(纯 JDBC 测试)等。

3. 应用上下文缓存

  • 复用机制:相同配置的测试类共享同一个 Spring 上下文,避免重复启动耗时。
  • 条件触发:通过 @DirtiesContext 标记需要重置上下文的测试,确保隔离性。

4. 依赖模拟(Mocking)

  • @MockBean / @SpyBean:利用 Mockito 创建模拟对象,替换 Spring 容器中的实际 Bean。

    • 示例:在测试 Service 层时,模拟 Repository 层,避免真实数据库操作。
  • 隔离测试:通过模拟外部依赖(如数据库、API 调用),确保测试专注于当前代码单元。


5. 测试配置与属性覆盖

  • 专用配置文件:通过 src/test/resources/application.properties 提供测试专用配置(如使用 H2 数据库)。
  • 动态属性覆盖:在测试中使用 @TestPropertySource 或 @DynamicPropertySource 动态修改配置(如随机端口)。

6. 工具类与实用方法

  • MockMvc:模拟 HTTP 请求,验证 Controller 的响应状态、JSON 结构等。

    @WebMvcTest(UserController.class)
    class UserControllerTest {
        @Autowired
        private MockMvc mvc;
        
        @Test
        void getUser() throws Exception {
            mvc.perform(get("/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name").value("Alice"));
        }
    }
    
  • TestRestTemplate:在集成测试中发送真实 HTTP 请求(适用于随机端口测试)。

  • @Sql:执行 SQL 脚本初始化或清理测试数据。


7. 自动化配置(Auto-configuration)

  • 条件化加载:根据测试切片自动配置相关组件(如 @DataJpaTest 自动配置 Hibernate、DataSource)。
  • 排除无关组件:通过 @AutoConfigureTestDatabase 等注解覆盖默认配置,提升测试效率。

8. 测试生命周期管理

  • @BeforeEach / @AfterEach:在测试方法前后执行初始化或清理操作。
  • 事务回滚:默认在测试结束后回滚数据库操作,保持测试环境干净(可通过 @Rollback(false) 禁用)。

总结:单元测试 vs 集成测试

  • 单元测试:使用 Mockito 等工具模拟依赖,测试单个类或方法,不启动 Spring 上下文。
  • 集成测试:通过 @SpringBootTest 加载完整或部分上下文,验证组件间交互。

通过以上机制,Spring Boot 的测试框架在保证测试覆盖率和准确性的同时,极大简化了配置和依赖管理,使开发者能够快速编写高效、可维护的测试用例。