文章目录

SmartOA 测试基建在 7 月底集中升级(INF-1~8),目标很朴素:让测试真正拦住回归。四件套:本地 MySQL 测试基类(替代 Testcontainers)、PIT 变异测试、Playwright E2E 冒烟、JaCoCo 覆盖率基线,外加权限 3-way 一致性测试和 ObjectMother 测试数据工厂。这篇记录每件套解决的问题和配置要点。

一、为什么动测试基建

此前测试有三大问题:

二、件套 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 列引用一致性检查)。

🚨 教训:H2 测试 schema 与 prod MySQL schema 漂移 = 测试全过但 prod 500。删字段时同步检查链路:Entity → Mapper XML → schema-h2.sql → 测试 SQL → 前端 types.ts → 前端 .vue。

三、件套 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 恢复

九、踩坑清单(可直接复用)

  1. 假绿比没测试更危险:恒真断言跑过 100 次也拦不住 bug,PIT 变异测试专治这个
  2. 测试环境与生产一致:H2 schema 必须跟随生产 DDL 变更,删字段先查 schema-h2.sql
  3. 本地优先:Testcontainers 依赖 Docker,CI/本地没有就跑不了——本地 MySQL 基类更稳
  4. 覆盖率看趋势不看数字:JaCoCo 基线卡最低值,防止回退
  5. 权限点一致性自动化:3-way 测试(菜单/按钮/注解),人工核对永远有漏
  6. 造数统一:ObjectMother 工厂,测试数据字段不漏不串
✅ 最终成果:测试从「数量多但拦不住」变成「每层有真验证」:DAO 层 SQL 真跑 MySQL、Service 层 PIT 查假绿、HTTP 层破冰、E2E 冒烟保链路、权限点 3-way 锁死。CI 门禁 + PR 模板同步上线,季度腐化巡检机制落地。

评 论