跳到主要内容

单元测试

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向 yudao-cloud 项目的单元测试实践,系统性介绍如何基于 JUnit 5 与 Mockito 进行高质量单元测试;详解 yudao-spring-boot-starter-test 提供的测试基类(BaseDbUnitTest、BaseRedisUnitTest、BaseDbAndRedisUnitTest、BaseMockitoUnitTest)及其适用场景;说明 H2 内存数据库与 Redis Mock 在测试中的配置与使用;并结合随机数据生成工具 Podam 的使用,给出可复用的测试编写范式与最佳实践。

项目结构

围绕单元测试的关键文件分布如下:

  • 测试基类:位于 yudao-spring-boot-starter-test 模块的 ut 包中,提供不同环境的测试上下文(纯内存 DB、纯内存 Redis、DB+Redis、纯 Mockito)。
  • 测试配置:位于 yudao-spring-boot-starter-test 模块的 config 包中,负责 H2 SQL 初始化与 Redis Mock 启动。
  • 随机数据工具:位于 yudao-spring-boot-starter-test 模块的 util 包中,基于 Podam 生成 POJO 随机数据。
  • 依赖声明:在 yudao-spring-boot-starter-test 的 pom.xml 中声明了 JUnit 5、Mockito、H2、jedis-mock、Podam 等测试依赖。
  • 示例测试:各功能模块的测试类展示了如何继承测试基类、使用断言与 Mockito、以及结合随机数据与 SQL 初始化。

Mermaid Diagram Code:

graph TB
subgraph "测试基类"
BDU["BaseDbUnitTest.java"]
BRU["BaseRedisUnitTest.java"]
BDR["BaseDbAndRedisUnitTest.java"]
BMU["BaseMockitoUnitTest.java"]
end
subgraph "测试配置"
SITC["SqlInitializationTestConfiguration.java"]
RTC["RedisTestConfiguration.java"]
end
subgraph "随机数据"
RU["RandomUtils.java"]
end
subgraph "依赖"
POM["pom.xmlyudao-spring-boot-starter-test"]
end
BDU --> SITC
BDR --> SITC
BRU --> RTC
BDR --> RTC
POM --> BDU
POM --> BRU
POM --> BDR
POM --> BMU
POM --> RU

图表来源

章节来源

核心组件

  • BaseDbUnitTest:提供内存 H2 数据库的完整测试上下文,适用于需要真实 SQL 执行但又无需外部数据库的场景。通过 @Sql 清理脚本确保每个测试后数据隔离。
  • BaseRedisUnitTest:提供内存 Redis 的测试上下文,使用 Redisson 自动装配与内嵌 RedisMock 服务。
  • BaseDbAndRedisUnitTest:同时启用内存数据库与内存 Redis,适合跨存储层的集成测试。
  • BaseMockitoUnitTest:仅启用 Mockito 扩展,适合纯 Mock 的单元测试,不涉及数据库或 Redis。
  • SqlInitializationTestConfiguration:替代默认懒加载下的 SQL 初始化行为,确保测试启动时正确执行 schema/data 脚本。
  • RedisTestConfiguration:启动内嵌 RedisServer,支持多测试并发执行时的端口冲突规避。
  • RandomUtils:基于 Podam 的随机数据工厂,提供字符串、数字、日期、枚举、集合与 POJO 的批量生成,便于构造测试数据。

章节来源

架构总览

下图展示了测试基类与配置之间的关系,以及依赖注入顺序与作用域:

Mermaid Diagram Code:

graph TB
A["BaseDbUnitTest<br/>内存DB测试"] --> C["SqlInitializationTestConfiguration<br/>SQL初始化"]
A --> D["YudaoDataSourceAutoConfiguration<br/>数据源配置"]
A --> E["YudaoMybatisAutoConfiguration<br/>MyBatis配置"]
A --> F["MybatisPlusAutoConfiguration<br/>MyBatis Plus配置"]
G["BaseRedisUnitTest<br/>内存Redis测试"] --> H["RedisTestConfiguration<br/>Redis Mock启动"]
G --> I["YudaoRedisAutoConfiguration<br/>Redis配置"]
G --> J["RedissonAutoConfiguration<br/>Redisson自动装配"]
K["BaseDbAndRedisUnitTest<br/>DB+Redis测试"] --> L["SqlInitializationTestConfiguration"]
K --> M["YudaoDataSourceAutoConfiguration"]
K --> N["YudaoMybatisAutoConfiguration"]
K --> O["YudaoRedisAutoConfiguration"]
K --> P["RedisTestConfiguration"]
K --> Q["RedissonAutoConfiguration"]

图表来源

详细组件分析

测试基类与使用场景

  • BaseDbUnitTest:适用于需要真实 SQL 执行的场景,如 Mapper/Service 层对 H2 的 CRUD 验证。通过 @Sql 在测试结束后清理数据,保证测试隔离。
  • BaseRedisUnitTest:适用于缓存、分布式锁、消息队列等依赖 Redis 的逻辑,使用内嵌 RedisMock 避免外部依赖。
  • BaseDbAndRedisUnitTest:适用于跨存储层的业务流程,例如先写入 DB,再更新缓存,最后校验一致性。
  • BaseMockitoUnitTest:适用于纯逻辑单元测试,不访问数据库或 Redis,仅通过 Mock 验证业务分支与边界条件。

章节来源

H2 内存数据库配置与使用

  • SQL 初始化:通过 SqlInitializationTestConfiguration 在测试启动阶段执行 schema/data 脚本,确保测试前后的数据库状态一致。
  • 清理策略:BaseDbUnitTest 使用 @Sql 在每个测试方法结束后执行 clean.sql,避免测试间相互污染。
  • MyBatis/MyBatis Plus:自动装配包含 YudaoMybatisAutoConfiguration、MybatisPlusAutoConfiguration、MybatisPlusJoinAutoConfiguration,满足复杂查询与关联查询的测试需求。

Mermaid Diagram Code:

flowchart TD
Start(["测试启动"]) --> LoadCfg["加载 SqlInitializationTestConfiguration"]
LoadCfg --> InitDB["执行 schema/data 脚本"]
InitDB --> RunTest["执行具体测试方法"]
RunTest --> Clean["执行 clean.sql 清理"]
Clean --> End(["测试结束"])

图表来源

章节来源

Redis Mock 配置与使用

  • 内嵌 Redis:RedisTestConfiguration 启动 RedisServer,优先使用配置端口,若启动失败则忽略异常以兼容多容器并发场景。
  • 自动装配:BaseRedisUnitTest 与 BaseDbAndRedisUnitTest 导入 YudaoRedisAutoConfiguration 与 RedissonAutoConfiguration,确保缓存客户端可用。
  • 场景:适用于缓存读写、分布式锁、布隆过滤器等逻辑的单元测试。

Mermaid Diagram Code:

sequenceDiagram
participant T as "测试类"
participant R as "RedisTestConfiguration"
participant RS as "RedisServer"
participant RC as "Redis 客户端"
T->>R : 加载配置
R->>RS : 启动内嵌 Redis
RS-->>R : 返回实例
T->>RC : 执行缓存操作
RC-->>T : 返回结果

图表来源

章节来源

Mockito 在单元测试中的应用

  • 扩展启用:BaseMockitoUnitTest 通过 @ExtendWith(MockitoExtension.class) 启用 Mockito。
  • 常用模式:
    • @Mock:创建被测对象依赖的 Mock 实例。
    • @InjectMocks:将 Mock 注入到被测对象中。
    • when(...).thenReturn(...):定义桩函数返回值。
    • verify(...):验证交互次数与调用参数。
  • 示例参考:DataPermissionAnnotationInterceptorTest 展示了如何通过 Mockito 对 AOP 拦截器进行行为验证。

Mermaid Diagram Code:

sequenceDiagram
participant UT as "单元测试"
participant IM as "MockitoExtension"
participant OBJ as "被测对象"
participant MI as "MethodInvocation"
UT->>IM : 初始化测试
UT->>OBJ : 注入 @Mock 依赖
UT->>MI : stub when(...).thenReturn(...)
UT->>OBJ : 调用目标方法
UT->>MI : verify(...).times(n)
UT-->>UT : 断言结果

图表来源

章节来源

断言与测试方法命名规范

  • 断言风格:统一使用 JUnit 5 的 Assertions API,如 assertEquals、assertTrue、assertNull 等。
  • 测试方法命名:推荐使用“方法名_输入条件_期望结果”或“场景描述”的形式,便于阅读与维护。
  • 示例参考:IPUtilsTest 展示了对 IP 解析结果的断言与边界值测试。

章节来源

随机数据生成工具 Podam 的使用

  • RandomUtils 基于 PodamFactoryImpl,提供以下能力:
    • 随机字符串、整数、日期、布尔值、短整型等基础类型。
    • 针对 status/type 等字段的智能策略(如状态枚举、tinyint 范围)。
    • 随机 POJO 与集合生成,并支持二次消费回调以定制字段。
  • 使用建议:在测试准备阶段使用 randomPojo/randomPojoList 构造多样化测试数据,减少手写样板代码。

Mermaid Diagram Code:

classDiagram
class RandomUtils {
+randomString()
+randomLongId()
+randomInteger()
+randomDate()
+randomLocalDateTime()
+randomShort()
+randomSet(clazz)
+randomCommonStatus()
+randomEmail()
+randomMobile()
+randomURL()
+randomPojo(clazz, consumers)
+randomPojoList(clazz, consumers)
}

图表来源

章节来源

代码生成模板中的测试实践

  • serviceTest.vm 展示了在代码生成的测试模板中如何:
    • 使用 randomPojo 构造测试数据并插入 Mapper。
    • 使用 cloneIgnoreId 生成对比数据,验证查询条件的匹配与不匹配。
    • 组装请求 VO 并断言分页/筛选结果。
  • 该模板体现了“数据准备—执行—断言—清理”的完整测试闭环。

章节来源

依赖分析

yudao-spring-boot-starter-test 的 pom.xml 明确声明了测试所需的核心依赖:

  • JUnit 5:测试框架与扩展。
  • Mockito:Mock 对象与 when-then、verify 验证。
  • H2:内存数据库,替代真实 MySQL。
  • jedis-mock:Redis Mock,替代真实 Redis。
  • Podam:POJO 随机数据生成。

Mermaid Diagram Code:

graph LR
POM["pom.xmlyudao-spring-boot-starter-test"] --> JUP["JUnit 5"]
POM --> MIT["Mockito"]
POM --> H2["H2"]
POM --> JM["jedis-mock"]
POM --> POD["Podam"]

图表来源

章节来源

性能考虑

  • 内存数据库与内存 Redis:避免网络 IO 与持久化开销,提升测试执行速度。
  • SQL 初始化与清理:合理使用 @Sql 与 clean.sql,避免重复初始化带来的性能损耗。
  • 随机数据规模:RandomUtils 默认集合大小有限,避免一次性生成过多数据导致内存压力。
  • 并发测试:Redis Mock 在多容器并发场景下可能因端口占用导致启动失败,RedisTestConfiguration 已做容错处理。

故障排查指南

  • H2 SQL 初始化失败
    • 检查 SqlInitializationTestConfiguration 是否被正确加载。
    • 确认 schema/data 路径与文件存在且格式正确。
  • Redis 启动失败
    • 检查端口是否被占用;RedisTestConfiguration 已捕获异常,必要时手动释放端口。
  • 测试间数据污染
    • 确认 BaseDbUnitTest 的 @Sql 清理脚本是否生效;检查 clean.sql 是否覆盖所有相关表。
  • Mockito 注入失败
    • 确保 @InjectMocks 与 @Mock 正确标注;确认被测对象的依赖注入路径。

章节来源

结论

yudao-cloud 的单元测试体系以 yudao-spring-boot-starter-test 为核心,提供了从内存数据库、内存 Redis 到纯 Mockito 的多层次测试基类,并辅以 SQL 初始化与 Redis Mock 配置,以及基于 Podam 的随机数据生成工具。遵循本文的测试基类选择、断言规范与数据准备策略,可显著提升测试的稳定性、可维护性与执行效率。

附录

  • 测试基类选择建议
    • 仅逻辑测试:BaseMockitoUnitTest
    • 需要 SQL 执行:BaseDbUnitTest
    • 需要缓存操作:BaseRedisUnitTest
    • 跨存储层流程:BaseDbAndRedisUnitTest
  • 断言与命名建议
    • 使用 JUnit 5 断言 API,测试方法命名清晰表达前置条件与期望结果。
  • 随机数据使用建议
    • 使用 RandomUtils 快速生成多样化测试数据,必要时通过消费者回调定制字段。
用户文档
AI 助手
Agent 列表
请选择一个 Agent 开始对话
AI 问答