完成自动化测试套件实施(W1-W11)
W1-W3: 基线修复与测试基础设施搭建 - 修复 Jenkins JDK 21 兼容性,统一 E2E 目录,修复 storageState 冲突 - 搭建后端测试基类 BaseContractTest + Testcontainers PostgreSQL - 创建 TestDataFactory 链式构造,完善 Vitest 基座与 Playwright fixtures - 建立 docker-compose.test.yml 与测试数据隔离方案 W4-W5: 单元测试补齐(阶段 2) - 补齐 gym-member/gym-groupCourse/gym-checkIn/gym-payment 核心模块单元测试 - 补齐 gym-coach/manage-sys 模块单元测试 - 前端 utils/composables/stores 单元测试,37 文件 502 项测试 - JaCoCo 覆盖率门禁从 30% 调整至 55%,21 模块全部通过 W6-W7: 集成与契约测试(阶段 3) - Repository 集成测试:会员/团课/签到/支付关键表,Testcontainers 100% 通过 - Handler 集成测试:WebTestClient 覆盖正向/异常/权限路径 - 网关集成测试:JWT/RBAC/签名/限流/重试 - Flyway 迁移测试:验证迁移脚本可重复执行 - OpenAPI 契约测试:覆盖 ≥80% P0 接口,202 项契约测试 0 失败 - 跨模块契约测试:会员-支付-团课数据一致性 W8-W9: E2E 与用户旅程测试(阶段 4) - 管理员 Web 核心流程 E2E:用户/角色/菜单/字典/配置 - 小程序会员端核心页面 E2E:购卡/预约/签到 - 5 条 P0 用户旅程全链路自动化,60 条 journey 测试 0 失败 W10: 变异测试与质量门禁(阶段 5) - 后端 PIT 配置:pitest-maven 1.19.1 + JUnit 5,覆盖率阈值 55%/变异阈值 45% - P0 模块基线:manage-sys 48%,gym-member 30%,gym-payment 36% - 前端 StrykerJS 配置:utils/stores 变异测试,dateFormat.ts 70.83% - Jenkins 质量门禁:JaCoCo/PIT/E2E 统一检查,不达标阻断构建 W11: 持续运行与改进(阶段 6) - 测试指标收集脚本 scripts/collect-test-metrics.py + HTML 看板生成器 - Flaky Test 治理 SOP:检测→隔离→根因分析→修复→验证闭环 - 测试资产定期评审流程:月度/季度/事件驱动三级机制 - 快速参考指南 docs/testing/quick-reference.md - 累计 10 份测试文档,7 个里程碑全部达成
This commit was merged in pull request #54.
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-manage-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>manage-common-test</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Manage Common Test</name>
|
||||
<description>共享测试基类与测试工具,供其他模块以 test scope 依赖</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- JUnit 5 -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Mockito -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- AssertJ -->
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Reactor Test -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- WebFlux Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- R2DBC H2 for fast local integration tests -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<artifactId>r2dbc-h2</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Allure JUnit 5 集成 -->
|
||||
<dependency>
|
||||
<groupId>io.qameta.allure</groupId>
|
||||
<artifactId>allure-junit5</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Testcontainers PostgreSQL/Redis (optional, for CI/nightly) -->
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.novalon.gym.manage.common.test;
|
||||
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 集成测试基类。
|
||||
*
|
||||
* <p>子类需自行添加具体的 Spring Boot 测试注解,例如:</p>
|
||||
* <pre>
|
||||
* {@literal @}SpringBootTest(classes = MyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
* class MyIntegrationTest extends IntegrationTestBase {
|
||||
* // ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>对于更轻量的数据库测试,建议使用:</p>
|
||||
* <pre>
|
||||
* {@literal @}DataR2dbcTest
|
||||
* {@literal @}Import({R2dbcConfig.class, MyConverter.class})
|
||||
* class MyRepositoryTest extends IntegrationTestBase {
|
||||
* // ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>默认激活 {@code test} profile,该 profile 已排除 Redis/Elasticsearch 自动配置,
|
||||
* 并优先使用 H2 R2DBC 以加速本地反馈。CI nightly 可切换为 Testcontainers PostgreSQL。</p>
|
||||
*/
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
public abstract class IntegrationTestBase {
|
||||
// 公共工具方法可后续补充,例如统一的数据库清理、WebTestClient 配置等
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package cn.novalon.gym.manage.common.test;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* 测试用唯一标识生成器。
|
||||
*
|
||||
* <p>提供线程安全的自增序列,保证同一 JVM 内多次调用不会产生重复 ID/编号/手机号,
|
||||
* 避免并行测试或快速连续执行时出现唯一约束冲突。</p>
|
||||
*/
|
||||
public final class TestIds {
|
||||
|
||||
private static final AtomicLong SEQUENCE = new AtomicLong(Instant.now().getEpochSecond());
|
||||
|
||||
private TestIds() {
|
||||
// 工具类禁止实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一 Long 类型 ID。
|
||||
*/
|
||||
public static Long nextId() {
|
||||
return SEQUENCE.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带前缀的唯一字符串标识。
|
||||
*
|
||||
* @param prefix 前缀,例如 {@code "M"}、{@code "ORD"}
|
||||
*/
|
||||
public static String nextCode(String prefix) {
|
||||
return prefix + SEQUENCE.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一手机号(11 位,以 138 开头)。
|
||||
*/
|
||||
public static String nextPhone() {
|
||||
long seq = SEQUENCE.incrementAndGet();
|
||||
return "138" + String.format("%08d", seq % 100_000_000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一会员号。
|
||||
*/
|
||||
public static String nextMemberNo() {
|
||||
return nextCode("M");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一订单号。
|
||||
*/
|
||||
public static String nextOrderNo() {
|
||||
return nextCode("ORD");
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package cn.novalon.gym.manage.common.test;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* 纯单元测试基类。
|
||||
*
|
||||
* <p>仅启用 Mockito,不加载 Spring 上下文,适合测试 Service / Handler / Util / Domain / Converter。
|
||||
* 子类应通过 {@code @Mock} 注入依赖,通过 {@code @InjectMocks} 创建被测对象。</p>
|
||||
*
|
||||
* <p>使用示例:</p>
|
||||
* <pre>
|
||||
* class MyServiceTest extends UnitTestBase {
|
||||
* {@literal @}Mock MyRepository repository;
|
||||
* {@literal @}InjectMocks MyService service;
|
||||
*
|
||||
* {@literal @}Test
|
||||
* void shouldDoSomething() {
|
||||
* when(repository.findById(1L)).thenReturn(Mono.just(new Entity()));
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public abstract class UnitTestBase {
|
||||
// 公共工具方法可后续补充,例如固定时钟、统一断言帮助方法等
|
||||
}
|
||||
Reference in New Issue
Block a user