Files
cn-rdms/rdms-framework/rdms-spring-boot-starter-test/README.md
2026-03-11 19:32:37 +08:00

374 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# rdms-spring-boot-starter-test
## 1. 模块定位
`rdms-spring-boot-starter-test` 是项目中的测试基础模块,作用不是提供业务测试用例,而是为测试提供统一的基础设施和基类。
当前模块主要解决的是:
- 纯 Mockito 单元测试怎么写
- 依赖数据库的单元测试怎么快速启动
- 依赖 Redis 的单元测试怎么快速启动
- 同时依赖 DB 和 Redis 的测试怎么快速启动
- 测试里怎么更方便地造随机数据和做断言
所以这个模块更适合理解为“测试脚手架模块”。
## 2. 设计思路
当前模块的设计思路比较明确:把常见测试场景抽成几种固定模板,让开发人员通过继承基类快速开始写测试,而不是每个模块都自己从零搭测试环境。
整体上分成三层:
1. 依赖层
统一引入测试常用依赖,例如 Mockito、Spring Boot Test、H2、内存 Redis、随机对象生成工具。
2. 配置层
提供针对测试场景的补充配置,例如:
- 内存 Redis 启动配置
- SQL 初始化配置
3. 基类层
把测试场景收口成几类基类,开发时按场景继承即可。
这种设计的重点不是“测试能力多复杂”,而是“让测试环境标准化”。
## 3. 当前提供的能力
### 3.1 纯 Mockito 单元测试基类
基类:
- `BaseMockitoUnitTest`
作用:
- 适合不需要 Spring 容器、不需要 DB、不需要 Redis 的纯单元测试
- 基于 `MockitoExtension`
适用场景:
- 测试工具类
- 测试纯业务逻辑类
- 依赖全部可以通过 Mock 替代的 Service
### 3.2 内存 DB 单元测试基类
基类:
- `BaseDbUnitTest`
作用:
- 启动 Spring 测试上下文
- 引入数据源、事务、MyBatis 相关配置
- 使用 H2 作为内存数据库
- 支持 SQL 初始化
- 每个测试方法结束后自动执行 `/sql/clean.sql` 清理数据库
适用场景:
- Mapper 测试
- 依赖本模块数据库访问的 Service 测试
- 需要真实执行 MyBatis SQL 的测试
### 3.3 内存 Redis 单元测试基类
基类:
- `BaseRedisUnitTest`
作用:
- 启动 Spring 测试上下文
- 启动内存 Redis
- 引入 Redis 与 Redisson 相关配置
适用场景:
- Redis DAO 测试
- 缓存逻辑测试
- 分布式锁、限流、缓存等依赖 Redis 的逻辑测试
### 3.4 内存 DB + Redis 组合测试基类
基类:
- `BaseDbAndRedisUnitTest`
作用:
- 同时启动内存数据库和内存 Redis
- 一次性引入 DB、MyBatis、Redis、Redisson 所需配置
- 每个测试方法结束后自动清理数据库
适用场景:
- 同时依赖数据库和缓存的 Service 测试
- 需要验证“写库 + 删缓存 / 刷缓存”这类联动逻辑的测试
### 3.5 内存 Redis 启动配置
配置类:
- `RedisTestConfiguration`
作用:
- 基于 `jedis-mock` 启动一个内存 Redis Server
- 供 Redis 相关测试基类复用
这个配置的重点是:让测试不依赖外部真实 Redis 服务。
### 3.6 SQL 初始化配置
配置类:
- `SqlInitializationTestConfiguration`
作用:
- 在测试场景下补充 DataSource SQL 初始化能力
- 解决延迟加载场景下默认 SQL 初始化配置不生效的问题
这个配置的核心价值是:保证 H2 测试数据库能按测试配置正常初始化 schema 和 data。
### 3.7 随机测试数据工具
工具类:
- `RandomUtils`
作用:
- 随机生成字符串、数字、时间、邮箱、手机号
- 随机生成 POJO
- 随机生成对象列表、对象集合
它内部基于 `podam` 做随机对象填充,并对部分字段做了定制处理,例如:
- `status` 字段优先生成常见状态值
- `deleted` 字段默认生成 `false`
- `LocalDateTime` 的纳秒位归零,避免 MySQL / H2 时间精度差异
### 3.8 测试断言工具
工具类:
- `AssertUtils`
作用:
- 对比两个 POJO 的字段是否一致
- 断言是否抛出指定 `ServiceException`
适用场景:
- 校验 DTO / DO / VO 转换结果
- 校验业务异常是否符合预期
## 4. 开发人员怎么上手
这个模块最重要的不是“看懂代码”,而是先判断当前测试属于哪一类,然后继承对应基类。
### 4.1 如果只是纯逻辑测试
直接继承:
```java
class XxxServiceTest extends BaseMockitoUnitTest {
}
```
适合:
- 不需要 Spring 容器
- 不访问数据库
- 不访问 Redis
- 依赖都可以 Mock
这是成本最低、执行最快的一类测试。
### 4.2 如果要测 Mapper 或真实 SQL
直接继承:
```java
class XxxMapperTest extends BaseDbUnitTest {
}
```
适合:
- Mapper 层测试
- 依赖 H2 跑 SQL
- Service 里要真实查库、写库
开发时通常要准备:
- `application-unit-test.yaml`
- 初始化 SQL
- `clean.sql`
### 4.3 如果要测 Redis 逻辑
直接继承:
```java
class XxxRedisDaoTest extends BaseRedisUnitTest {
}
```
适合:
- Redis Key 操作测试
- 缓存逻辑测试
- 基于 Redis 的基础设施测试
这样就不需要自己额外准备 Redis 环境。
### 4.4 如果业务同时依赖 DB 和 Redis
直接继承:
```java
class XxxServiceTest extends BaseDbAndRedisUnitTest {
}
```
适合:
- 先写库再删缓存
- 先查库再写缓存
- 依赖数据库和 Redis 共同完成的业务逻辑
### 4.5 如果想快速造测试对象
可以直接使用 `RandomUtils`
```java
UserSaveReqVO reqVO = RandomUtils.randomPojo(UserSaveReqVO.class);
List<UserSaveReqVO> list = RandomUtils.randomPojoList(UserSaveReqVO.class, 3);
String email = RandomUtils.randomEmail();
String mobile = RandomUtils.randomMobile();
```
适合:
- 减少手写测试数据
- 快速生成大量测试输入
- 配合局部字段覆盖提高测试效率
### 4.6 如果要断言业务异常
可以直接使用 `AssertUtils.assertServiceException(...)`
```java
AssertUtils.assertServiceException(
() -> userService.createUser(reqVO),
USER_USERNAME_EXISTS
);
```
适合:
- 校验业务校验逻辑
- 校验异常码和异常信息
### 4.7 如果要断言对象字段一致
可以使用:
```java
AssertUtils.assertPojoEquals(expected, actual, "createTime", "updateTime");
```
适合:
- 校验转换逻辑
- 校验查询结果
- 忽略少数字段差异后做整体对比
## 5. 常见使用建议
### 5.1 优先选最轻的测试基类
建议顺序是:
1. 能用 `BaseMockitoUnitTest` 就不要上 Spring 容器
2. 需要真实 DB 再用 `BaseDbUnitTest`
3. 需要真实 Redis 再用 `BaseRedisUnitTest`
4. 两者都需要时再用 `BaseDbAndRedisUnitTest`
原因很简单:
- 测试越轻,执行越快
- 环境越少,问题越少
### 5.2 本模块更偏“单元测试基础设施”
虽然这里用到了 Spring Boot Test、H2、内存 Redis但当前命名和设计仍然偏“单元测试 / 轻量集成测试”。
也就是说,它更适合:
- 在模块内部验证逻辑正确性
- 快速验证 Mapper / Redis / Service 行为
而不是:
- 完整端到端测试
- 完整微服务联调测试
- 依赖真实外部中间件的系统测试
### 5.3 自己模块真实依赖走内存实现,外部模块依赖走 Mock
`BaseDbUnitTest` 的注释就能看出当前设计思路:
- 自己模块的 Mapper 走 H2
- 别的模块的 Service 走 Mock
这是一种比较务实的测试策略:
- 保留自己模块的真实数据访问能力
- 避免跨模块依赖把测试拖重
## 6. 模块边界
当前模块负责的是:
- 提供测试基类
- 提供测试配置
- 提供随机数据和断言工具
当前模块不负责的是:
- 自动生成业务测试用例
- 自动替你写 Mock 行为
- 真实中间件联调
- 完整集成测试平台
所以它的职责很明确:让测试环境更容易搭,不是替业务写测试。
## 7. 总结
`rdms-spring-boot-starter-test` 当前已经把项目里最常见的测试场景做成了统一模板。
对于开发人员来说,真正重要的上手方式只有两步:
1. 先判断当前测试依赖什么环境
2. 再继承对应的基类
如果只是想快速理解这个模块,可以直接记住下面这张映射:
- 纯逻辑测试:`BaseMockitoUnitTest`
- 测 DB`BaseDbUnitTest`
- 测 Redis`BaseRedisUnitTest`
- DB + Redis 一起测:`BaseDbAndRedisUnitTest`
再配合:
- `RandomUtils` 造数据
- `AssertUtils` 做断言
基本就能覆盖大部分日常测试开发场景。