Files
iot-dc3/docs/development/testing.md
T
pnoker b674385904 docs: update documentation and README
Refresh architecture, development, operations, and quickstart docs.
Update multi-language README files.
2026-06-11 00:31:34 +08:00

6.4 KiB

测试

本页是 IoT DC3 后端仓库的测试参考。它补充根目录 AGENTS.md 的工程规则,以及 日志规范 和 环境变量。

测试金字塔

层级 目标 技术方式 说明
单元测试 快速验证孤立业务逻辑 JUnit 5、Mockito、AssertJ 不启动完整 Spring 上下文
Slice 测试 验证 Controller、JSON、持久化切片 @WebFluxTest、@JsonTest、MyBatis 相关测试 聚焦框架边界
集成测试 验证真实基础设施和跨模块协作 Testcontainers、gRPC InProcess、RabbitMQ harness 使用 PostgreSQL、RabbitMQ、MQTT 等容器
E2E 测试 验证端到端业务链路 dc3-e2e、Testcontainers、rest-assured 由 DC3_E2E 控制启用

覆盖率门槛

聚合覆盖率门槛由 dc3-coverage/pom.xml 控制:

指标 当前门槛
行覆盖率 20%
分支覆盖率 15%

当前门槛相对克制,便于在测试体系扩展过程中持续推进。提高门槛时,应同时提交能够支撑新门槛的测试。

目录和命名

建议测试目录结构:

<module>/src/test/
├── java/<package>/
│   ├── unit/           # *Test.java; Surefire 执行
│   ├── slice/          # *SliceTest.java; WebFlux / JSON / DAL 切片
│   ├── integration/    # *IT.java; Failsafe 执行
│   ├── contract/       # *ContractTest.java; 复用 dc3-common-test 基类
│   └── support/        # 模块专用 fixture 和 test double
└── resources/
    ├── application-test.yml
    ├── fixtures/
    └── logback-test.xml

命名规则:

  • 单元测试:*Test.java。
  • 集成测试:*IT.java。
  • 测试方法建议使用 should_<expected>_when_<condition> 或 given_<state>__when_<action>__then_<outcome>。
  • 断言使用 AssertJ,不引入 JUnit 4 断言。
  • Mock 使用 Mockito 5;禁止引入 PowerMock。
  • fixture 放在 src/test/resources/fixtures/,文件名体现功能和场景。

何时必须补测试

变更类型 要求
Bug 修复 增加能复现问题的回归测试
新功能或行为变化 增加单元测试,并按风险补 slice / integration 测试
重构 保持现有覆盖,隐式契约应补 contract 测试
DAL / SQL 变更 增加 Testcontainers 测试,并运行 make test-it
gRPC proto 变更 同步更新服务端、客户端和契约测试
纯文档或格式变更 不需要 Java 测试,但需要文档构建或格式检查

时间、随机数和 IO

  • 注入 java.time.Clock,不要直接调用 LocalDateTime.now()。
  • 需要固定时间时使用 FixedClockConfig。
  • 随机逻辑使用可注入或固定 seed 的 RandomGenerator。
  • 静态工具可用 Mockito.mockStatic(...),放在 try-with-resources 中。
  • WebFlux 使用 WebTestClient;不要使用 MockMvc。
  • gRPC 测试使用 grpc-testing 和 InProcessChannelBuilder,不打开真实 socket。
  • 异步等待使用 Awaitility,禁止在测试中裸用 Thread.sleep。

Testcontainers 约定

共享容器包装器位于:

dc3-common/dc3-common-test/src/main/java/io/github/pnoker/test/containers/

常用容器:

容器 镜像 用途
PostgreSQL / TimescaleDB timescale/timescaledb-ha:pg18 数据库和时序表测试
RabbitMQ rabbitmq:3.13-management 消息发布、确认和消费测试
MQTT eclipse-mosquitto:2.0 MQTT 驱动测试

本地复用容器是可选能力,可在支持的环境中创建:

testcontainers.reuse.enable=true

测试数据

  • 小型固定载荷放在 src/test/resources/fixtures/,便于 review diff。
  • 大量对象生成使用 Instancio,并固定 seed。
  • 数据库初始状态通过测试资源中的 SQL 或 Testcontainers 初始化脚本准备。
  • fixture 中的敏感字段使用 should-not-leak 等显式占位值,避免误泄漏。

契约测试

dc3-common-test 提供可复用契约测试基类:

基类 用途
EnumContractTest<E> 验证枚举 getIndex() 唯一、ofIndex() 往返和常量稳定性
SecretFieldContractTest 验证 apiKey、password、secret、token 等字段不从 toString() 或序列化中泄漏

新增通用契约测试时,应放在能合理访问目标类型的模块中,避免反向依赖。

本地命令

make test                 # 单元测试
make test-it              # 集成测试,需要 Docker/Podman 可用
make coverage             # 聚合 JaCoCo 报告
make test-e2e             # E2E 测试,设置 DC3_E2E=true
mvn -B -pl <module> test  # 指定模块单元测试

make coverage 生成报告:

dc3-coverage/target/site/jacoco-aggregate/

CI 工作流

Workflow 触发 主要任务
ci.yml push / PR 到 develop、release、main 快速编译
test.yml push / PR 到 develop、release、main unit、integration、coverage
e2e.yml push 到 develop、release、main 或手动触发 E2E

PR 合并前应关注:

  • unit 和 integration job 通过。
  • coverage job 上传 jacoco-aggregate artifact。
  • 覆盖率低于 dc3-coverage/pom.xml 门槛会阻断。
  • 行为变更应说明已验证内容和未验证风险。