# 业务集成测试编写指南

## 文档定位

本指南用于约束基于 Ineed-Core 开发业务模块时的 Java 业务集成测试写法。

当一个业务聚合已经包含 CRUD、状态流转、多对多关系、认证/授权接入、级联删除或多数据栈实现时，不能只依赖零散单元测试。模块应提供一个稳定的全业务集成测试入口，用于每次改完模块后的主回归验证。

## 验证层级与证据

先按[测试规范](../standards/testing.md)区分内存/Mock 契约测试、真实数据库、Spring/HTTP 和前端 E2E。类名含 Integration 或调用 Controller 方法不等于已经验证事务代理、授权或真实数据库。报告应包含命令、实际数量、结果和未验证项。

## 主回归入口

每个复杂业务聚合推荐保留一个语义清晰的全业务集成测试类，例如：

- `XxxBusinessIntegrationTest`
- `XxxBusinessScenarioTest`
- `XxxFullBusinessIntegrationTest`

该测试类不替代低层单元测试，而是作为模块级主回归入口，覆盖从业务入口到持久化结果的完整链路。

命名和职责要求：

- 测试类名表达业务对象或业务聚合，不按技术栈命名。
- 测试方法按业务场景命名，不按内部实现方法命名。
- 测试覆盖真实业务结果，不只验证 mock 调用次数。
- 每次修复多对多、级联删除、权限分配、认证加载等核心链路后，应优先运行该集成测试。

## 覆盖范围

全业务集成测试至少覆盖以下维度：

- 主对象创建、查询、编辑。
- 启用、停用、锁定、解锁等已声明的数据状态能力。
- 逻辑删除、恢复、物理删除。
- 多对多关系写入、替换、清空和读取。
- 前端分配类接口对应的读列表与保存关系两类动作。
- 认证/授权类查询，例如加载当前主体的分组、角色、权限或数据范围。
- 逻辑删除数据、未启用数据、跨租户数据等不应出现在业务结果中的过滤规则。
- 物理删除后的关系表、从表、后代节点或绑定关系级联清理。

如果业务对象本身没有某类能力，可以不测该能力；但测试代码或测试说明应体现这是业务能力缺失，而不是遗漏。

## 多对多场景测试

多对多关系测试必须覆盖业务结果，而不是只覆盖保存方法返回成功。

推荐场景：

1. 创建主对象和多个目标对象。
2. 调用分配接口保存目标对象 ID 集合或授权集合。
3. 查询已分配对象列表，断言返回 VO 包含目标对象，并且字段满足前端展示需要。
4. 再次调用分配接口替换为另一批目标对象，断言旧关系消失、新关系存在。
5. 调用空集合分配，断言关系被清空。
6. 将目标对象逻辑删除或停用后，断言已分配对象列表或认证结果不再返回该对象。

落层期望：

- 写关系时，`Service` 只做 ID / 授权模式归一化和主对象状态校验。
- 查询已分配对象列表时，由主对象 `Manager` 通过 join 返回 VO。
- 测试应能暴露“Service 先查 ID 再回查对象”的旧模式遗漏过滤条件或绕路查询的问题。

## 级联删除场景测试

级联删除测试必须证明删除后的数据状态符合业务约束。

推荐场景：

- 删除主对象后，关系表中该主对象的关系被清理。
- 删除目标对象后，关系表中指向该目标对象的关系被清理。
- 删除树形节点后，后代节点按业务规则被物理删除或被禁止删除。
- 删除前存在外键或强依赖时，`beforePhysicsDelete` 中的清理足以保证主对象物理删除成功。
- 逻辑删除不应物理清理可恢复关系，除非业务需求明确要求不可恢复。

断言要求：

- 不只断言删除方法没有抛异常。
- 必须查询关系表、从表或业务读取结果，确认级联结果。
- `forceDelete` 测试只验证跳过状态判断后进入物理删除流程；不要假设存在独立的 `beforeForceDelete` / `afterForceDelete` 钩子。

## 认证与授权场景测试

如果模块参与认证或授权链路，业务集成测试应覆盖认证入口用到的关键查询。

推荐场景：

- 创建可认证主体和相关分组、角色、权限或数据范围。
- 建立必要关系后，通过认证/授权服务加载业务快照。
- 断言快照中包含有效关系。
- 停用或逻辑删除相关对象后，再次加载并断言结果已剔除无效对象。
- 替换关系后，断言旧关系不再影响认证/授权结果。

该类测试应验证业务快照内容，不应只 mock 底层 manager。

## 多数据栈对齐

同一业务聚合如果同时实现 `jpa / jdbc / mybatis-flex / r2dbc`，测试策略应同步评估四条线。

推荐做法：

- 先跑与业务规则无关的单元测试。
- 再跑阻塞式主链路集成测试。
- 再跑响应式主链路集成测试。
- 对 JPA、JDBC、MyBatis-Flex、R2DBC 的核心行为保持同一组业务场景和断言语义。

数据栈差异只允许体现在测试启动配置、事务方式、返回类型和等待方式上；业务断言不能漂移。

JPA 与 MyBatis-Flex 是优先优化路径：

- JPA 测试应能覆盖 QueryDSL / ORM 查询是否剔除逻辑删除和未启用数据。
- MyBatis-Flex 测试应能覆盖 `QueryWrapper` / `TableDef` 查询是否与 JPA 语义一致。
- JDBC / R2DBC 当前允许保持集中 SQL 实现，但测试仍应约束返回结果一致。

## 响应式测试要求

响应式测试必须验证订阅期行为。

- 使用 `StepVerifier` 或等价方式订阅 `Mono` / `Flux`。
- 不用同步 `assertThrows(...)` 断言 Publisher 创建期异常。
- 对动作型方法，阻塞式为 `void` 时，响应式统一断言 `Mono<Void>` 完成或错误。
- 对集合查询，断言元素内容和数量，不只断言 `Flux` 非空。

如果阻塞式和响应式同时存在，测试场景名称、前置数据和业务断言应保持一致。

## 权限与前端分配接口

对前端分配类接口，应同时测试“读已分配列表”和“提交分配结果”。

这两个动作通常服务于同一个页面操作，权限点也应保持一致：

- 读已分配列表用于打开分配弹窗或分配页面。
- 提交分配结果用于保存关系。
- 测试应覆盖用户具备该分配权限时，两类接口都可完成业务动作。
- 如果读列表和提交关系拆成两个 resource key，应先确认是否确实存在两个独立授权动作。

权限清单测试或权限清单扫描应避免为同一个分配动作生成多余权限点。

## 推荐执行命令

模块级回归命令应写在任务说明、PR 描述或模块文档中。

示例：

```bash
mvn -pl <module-core>,<module-engine>,<module-engine-reactive>,<module-jpa>,<module-jdbc>,<module-mybatis-flex>,<module-r2dbc>,<module-webmvc>,<module-webflux> -am test -DskipTests=false -Dmaven.javadoc.skip=true
```

如果只改了某一条线，也可以先跑局部测试，但最终合并前仍应运行覆盖业务聚合主链路的回归命令。

## 禁止写法

- 只测 converter、mapper 或 repository，不测业务入口到结果的完整链路。
- 只断言方法被调用，不断言数据库或业务返回结果。
- 多对多只测保存成功，不测替换、清空、过滤和读取。
- 级联删除只测删除不报错，不查关系表或从表清理结果。
- 响应式测试用同步 `assertThrows(...)` 断言订阅期错误。
- JPA 测试通过后，在实现中保留 native SQL 多对多查询。
- 只维护 WebMvc 测试，完全忽略 WebFlux 对等能力，除非需求明确排除响应式链路。

> 最后更新：2026-05-15
