文章目录
SmartOA 测试基建在 7 月底集中升级(INF-1~8),目标很朴素:让测试真正拦住回归。四件套:本地 MySQL 测试基类(替代 Testcontainers)、PIT 变异测试、Playwright E2E 冒烟、JaCoCo 覆盖率基线,外加权限 3-way 一致性测试和 ObjectMother 测试数据工厂。这篇记录每件套解决的问题和配置要点。
一、为什么动测试基建
此前测试有三大问题:
- 假绿:测试断言没写到位(恒真断言),跑过了等于没跑——WeatherCardServiceTest 假绿断言就是典型
- 假并发:测试里用多线程「看起来测了并发」,实际没验证任何并发不变量
- 假环境:H2 内存库与生产 MySQL 行为漂移(删列后 H2 schema 没同步,测试全过但 prod 炸)
二、件套 1:Testcontainers → 本地 MySQL 测试基类
原来用 Testcontainers 起 MySQL 容器测 DAO,问题:CI/本地没 Docker 就跑不了。改为本地 MySQL + 测试基类:
// 测试基类:连本地 MySQL 测试库,自动建 schema + 清理数据
@SpringBootTest
public abstract class MySqlTestBase {
@BeforeEach
void resetDb() {
// TRUNCATE 业务表 + 重置自增,保证用例独立
}
}
3 个原来 @Disabled 的测试迁移到新基类后全部启用。配套:schema-h2.sql 与生产 schema 同步检查——删字段时必须同步改 H2 测试 schema,否则「测试假绿、生产炸」(P0-1 事故教训:Mapper XML 列引用一致性检查)。
三、件套 2:PIT 变异测试
覆盖率 90% 也可能全是假绿——变异测试能测出「断言根本没起作用」。PIT(pitest)会故意改坏代码(把 > 改成 >=、删掉一行),如果测试没拦住变异体,说明断言无效:
// pom.xml:PIT 配置 + 首份报告
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.15.0</version>
<configuration>
<targetClasses>
<param>com.smartoa.itam.*</param>
</targetClasses>
<mutationThreshold>80</mutationThreshold>
</configuration>
</plugin>
首份报告的发现:核心 Service 的变异存活率偏高,尤其是状态机 CAS 边界条件——补了边界测试后变异存活率显著下降。PIT 的价值:它告诉你测试「信不信得过」,而不是「多不多」。
四、件套 3:Playwright E2E 冒烟流
前端单测(Vitest)覆盖组件逻辑,但登录 → 首页 → 关键业务页的完整链路没人测。Playwright 配冒烟流:
// playwright.config.ts:冒烟流配置
export default defineConfig({
testDir: './e2e',
use: { baseURL: 'http://localhost:8081' },
projects: [
{ name: 'smoke', testMatch: /smoke\.spec\.ts/ }
]
});
冒烟用例:登录(正确/错误密码)→ 首页加载 → 审批列表 → 资产管理页 → 退出登录。每个都是「页面能渲染 + 关键 API 返回 200」级别,跑完 2 分钟内给出「系统没坏」的结论。
五、件套 4:JaCoCo 覆盖率基线
先定基线再谈提升:JaCoCo 生成覆盖率报告,把当前值作为基线记录,后续合并不允许低于基线:
// pom.xml:JaCoCo 覆盖率检查
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits><limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.60</minimum> // 基线 60%
</limit></limits>
</rule>
</rules>
</configuration>
</plugin>
前端 coverage 同时纳入 components 目录(不只是工具函数),避免「测的全是 utils,业务组件裸奔」。
六、配套:3-way 权限一致性测试
权限点是安全命脉,三处定义必须一致:前端菜单权限点 / 前端按钮权限点 / 后端 @SaCheckPermission 注解。写了一个参数化批量验证测试(P1-3):
// 3-way 一致性:前端声明的权限点,后端必须有对应注解
@ParameterizedTest
@MethodSource("frontendPermissionPoints")
void frontendPointHasBackendGuard(String point) {
assertTrue(backendHasAnnotation(point),
"前端权限点 " + point + " 后端无 @SaCheckPermission");
}
这套测试直接抓出 14 处前端独有权限点错配 + hyphenated/camelCase 不一致(P1-1 第二批)。
七、测试数据工厂:ObjectMother
测试里到处 new 实体、字段漏填导致测试间互相踩。ObjectMother 统一造数:
// TestFixtures:统一测试数据工厂
public final class TestFixtures {
public static Employee employee(Long id) {
return new Employee()
.setEmployeeId(id)
.setUsername("user_" + id)
.setStatus(1);
}
public static ItamFixedAsset asset(String no) { /* ... */ }
}
配合补测:CompoundCache 多级缓存测试、Controller HTTP 测试破冰(P0-6,第一个真正的 HTTP 层测试)、事件体系 6 个发布端补测(P0-5)、EmployeeService mock 补全(P0-5)。
八、成果数据
| 指标 | 升级前 | 升级后 |
|---|---|---|
| 后端测试文件 | — | 168 文件 / 1201 @Test |
| 前端测试 | — | 36 文件 / 328 用例 |
| 假并发测试 | 存在 | 改写为真并发验证 |
| 假绿断言 | 存在(WeatherCard) | 修复 + 历史事故回归测试 |
| DAO SQL 测试 | Testcontainers(需 Docker) | 本地 MySQL 基类,3 个 @Disabled 恢复 |
九、踩坑清单(可直接复用)
- 假绿比没测试更危险:恒真断言跑过 100 次也拦不住 bug,PIT 变异测试专治这个
- 测试环境与生产一致:H2 schema 必须跟随生产 DDL 变更,删字段先查 schema-h2.sql
- 本地优先:Testcontainers 依赖 Docker,CI/本地没有就跑不了——本地 MySQL 基类更稳
- 覆盖率看趋势不看数字:JaCoCo 基线卡最低值,防止回退
- 权限点一致性自动化:3-way 测试(菜单/按钮/注解),人工核对永远有漏
- 造数统一:ObjectMother 工厂,测试数据字段不漏不串
评 论