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

8.2 KiB
Raw Blame History

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 如果只是纯逻辑测试

直接继承:

class XxxServiceTest extends BaseMockitoUnitTest {
}

适合:

  • 不需要 Spring 容器
  • 不访问数据库
  • 不访问 Redis
  • 依赖都可以 Mock

这是成本最低、执行最快的一类测试。

4.2 如果要测 Mapper 或真实 SQL

直接继承:

class XxxMapperTest extends BaseDbUnitTest {
}

适合:

  • Mapper 层测试
  • 依赖 H2 跑 SQL
  • Service 里要真实查库、写库

开发时通常要准备:

  • application-unit-test.yaml
  • 初始化 SQL
  • clean.sql

4.3 如果要测 Redis 逻辑

直接继承:

class XxxRedisDaoTest extends BaseRedisUnitTest {
}

适合:

  • Redis Key 操作测试
  • 缓存逻辑测试
  • 基于 Redis 的基础设施测试

这样就不需要自己额外准备 Redis 环境。

4.4 如果业务同时依赖 DB 和 Redis

直接继承:

class XxxServiceTest extends BaseDbAndRedisUnitTest {
}

适合:

  • 先写库再删缓存
  • 先查库再写缓存
  • 依赖数据库和 Redis 共同完成的业务逻辑

4.5 如果想快速造测试对象

可以直接使用 RandomUtils

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(...)

AssertUtils.assertServiceException(
        () -> userService.createUser(reqVO),
        USER_USERNAME_EXISTS
);

适合:

  • 校验业务校验逻辑
  • 校验异常码和异常信息

4.7 如果要断言对象字段一致

可以使用:

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
  • 测 DBBaseDbUnitTest
  • 测 RedisBaseRedisUnitTest
  • DB + Redis 一起测:BaseDbAndRedisUnitTest

再配合:

  • RandomUtils 造数据
  • AssertUtils 做断言

基本就能覆盖大部分日常测试开发场景。