完成自动化测试套件实施(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,62 @@
|
||||
<?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-test-datafactory</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Manage Test Data Factory</name>
|
||||
<description>共享测试数据工厂,集中构造会员/教练/课程/订单/支付等业务的测试实体</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 共享测试基类与 ID 生成器 -->
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>manage-common-test</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务模块:会员、会员卡、会员卡记录 -->
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-member</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务模块:教练、违规记录 -->
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-coach</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务模块:团课、团课预约 -->
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-groupCourse</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务模块:支付订单 -->
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-payment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库实体:教练时间规则等 -->
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>manage-db</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package cn.novalon.gym.manage.test.datafactory;
|
||||
|
||||
import cn.novalon.gym.manage.common.test.TestIds;
|
||||
import cn.novalon.gym.manage.coach.entity.CoachViolationEntity;
|
||||
import cn.novalon.gym.manage.db.entity.CoachTimeRuleEntity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 教练相关测试数据工厂。
|
||||
*
|
||||
* <p>提供教练时间规则({@link CoachTimeRuleEntity})与违规记录({@link CoachViolationEntity})的默认构造。
|
||||
* 由于当前系统中“教练”本身复用系统用户模型,这里以教练业务相关的核心实体为代表。</p>
|
||||
*/
|
||||
public final class CoachDataFactory {
|
||||
|
||||
private CoachDataFactory() {
|
||||
// 工厂类禁止实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的教练时间规则实体。
|
||||
*/
|
||||
public static CoachTimeRuleEntity defaultTimeRule() {
|
||||
Long id = TestIds.nextId();
|
||||
CoachTimeRuleEntity rule = new CoachTimeRuleEntity();
|
||||
rule.setId(id);
|
||||
rule.setMinDuration(30);
|
||||
rule.setMaxDuration(120);
|
||||
rule.setNormalWindow(10);
|
||||
rule.setLateWindow(5);
|
||||
rule.setEndGrace(10);
|
||||
rule.setIsDefault(false);
|
||||
rule.setSortOrder(0);
|
||||
rule.setStatus("1");
|
||||
rule.setRemark("测试教练时间规则-" + id);
|
||||
rule.setCreateBy("test");
|
||||
rule.setUpdateBy("test");
|
||||
rule.setCreatedAt(LocalDateTime.now());
|
||||
rule.setUpdatedAt(LocalDateTime.now());
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个匹配指定课程时长的教练时间规则实体。
|
||||
*/
|
||||
public static CoachTimeRuleEntity timeRuleForDuration(int minDuration, int maxDuration) {
|
||||
CoachTimeRuleEntity rule = defaultTimeRule();
|
||||
rule.setMinDuration(minDuration);
|
||||
rule.setMaxDuration(maxDuration);
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一条默认的教练违规记录。
|
||||
*/
|
||||
public static CoachViolationEntity defaultViolation() {
|
||||
Long id = TestIds.nextId();
|
||||
CoachViolationEntity violation = new CoachViolationEntity();
|
||||
violation.setId(id);
|
||||
violation.setCoachId(TestIds.nextId());
|
||||
violation.setCourseId(TestIds.nextId());
|
||||
violation.setViolationTime(LocalDateTime.now());
|
||||
violation.setViolationReason("测试违规原因-" + id);
|
||||
violation.setCreatedAt(LocalDateTime.now());
|
||||
return violation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定教练与课程的违规记录。
|
||||
*/
|
||||
public static CoachViolationEntity violationOf(Long coachId, Long courseId) {
|
||||
CoachViolationEntity violation = defaultViolation();
|
||||
violation.setCoachId(coachId);
|
||||
violation.setCourseId(courseId);
|
||||
return violation;
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package cn.novalon.gym.manage.test.datafactory;
|
||||
|
||||
import cn.novalon.gym.manage.common.test.TestIds;
|
||||
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseBookingEntity;
|
||||
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseEntity;
|
||||
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseTypeEntity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 课程相关测试数据工厂。
|
||||
*
|
||||
* <p>提供团课({@link GroupCourseEntity})、团课类型({@link GroupCourseTypeEntity})
|
||||
* 与团课预约({@link GroupCourseBookingEntity})的默认构造。</p>
|
||||
*/
|
||||
public final class CourseDataFactory {
|
||||
|
||||
private CourseDataFactory() {
|
||||
// 工厂类禁止实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的团课类型实体。
|
||||
*/
|
||||
public static GroupCourseTypeEntity defaultCourseType() {
|
||||
Long id = TestIds.nextId();
|
||||
GroupCourseTypeEntity type = new GroupCourseTypeEntity();
|
||||
type.setId(id);
|
||||
type.setTypeName("瑜伽-" + id);
|
||||
type.setBaseDifficulty(3);
|
||||
type.setDescription("测试团课类型-" + id);
|
||||
type.setCategory("有氧");
|
||||
type.setCreatedAt(LocalDateTime.now());
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的团课实体。
|
||||
*/
|
||||
public static GroupCourseEntity defaultGroupCourse() {
|
||||
Long id = TestIds.nextId();
|
||||
LocalDateTime startTime = LocalDateTime.now().plusDays(1).withMinute(0).withSecond(0).withNano(0);
|
||||
GroupCourseEntity course = new GroupCourseEntity();
|
||||
course.setId(id);
|
||||
course.setCourseName("瑜伽团课-" + id);
|
||||
course.setCoachId(TestIds.nextId());
|
||||
course.setCourseType(TestIds.nextId());
|
||||
course.setStartTime(startTime);
|
||||
course.setEndTime(startTime.plusHours(1));
|
||||
course.setMaxMembers(20);
|
||||
course.setCurrentMembers(0);
|
||||
course.setActualStartTime(null);
|
||||
course.setActualEndTime(null);
|
||||
course.setStatus(0L);
|
||||
course.setLocation("测试教室 A");
|
||||
course.setCoverImage("https://example.com/course/" + id + ".png");
|
||||
course.setDescription("测试团课描述-" + id);
|
||||
course.setStoredValueAmount(BigDecimal.TEN);
|
||||
course.setQrCodePath(null);
|
||||
course.setCreatedAt(LocalDateTime.now());
|
||||
return course;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定教练与类型的团课实体。
|
||||
*/
|
||||
public static GroupCourseEntity groupCourseOf(Long coachId, Long courseTypeId) {
|
||||
GroupCourseEntity course = defaultGroupCourse();
|
||||
course.setCoachId(coachId);
|
||||
course.setCourseType(courseTypeId);
|
||||
return course;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的团课预约实体。
|
||||
*/
|
||||
public static GroupCourseBookingEntity defaultBooking() {
|
||||
Long id = TestIds.nextId();
|
||||
LocalDateTime startTime = LocalDateTime.now().plusDays(1);
|
||||
GroupCourseBookingEntity booking = new GroupCourseBookingEntity();
|
||||
booking.setId(id);
|
||||
booking.setCourseId(TestIds.nextId());
|
||||
booking.setMemberId(TestIds.nextId());
|
||||
booking.setMemberCardRecordId(TestIds.nextId());
|
||||
booking.setBookingTime(LocalDateTime.now());
|
||||
booking.setStatus("0");
|
||||
booking.setCancelTime(null);
|
||||
booking.setCourseName("瑜伽团课-" + id);
|
||||
booking.setCourseStartTime(startTime);
|
||||
booking.setCourseEndTime(startTime.plusHours(1));
|
||||
booking.setLocation("测试教室 A");
|
||||
booking.setCreatedAt(LocalDateTime.now());
|
||||
return booking;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定会员与课程的预约实体。
|
||||
*/
|
||||
public static GroupCourseBookingEntity bookingOf(Long memberId, Long courseId) {
|
||||
GroupCourseBookingEntity booking = defaultBooking();
|
||||
booking.setMemberId(memberId);
|
||||
booking.setCourseId(courseId);
|
||||
return booking;
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package cn.novalon.gym.manage.test.datafactory;
|
||||
|
||||
import cn.novalon.gym.manage.common.test.TestIds;
|
||||
import cn.novalon.gym.manage.member.entity.Member;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCard;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 会员相关测试数据工厂。
|
||||
*
|
||||
* <p>提供会员({@link Member})与会员卡({@link MemberCard})的默认构造与常见变体。
|
||||
* 所有标识类字段均使用 {@link TestIds} 生成,避免唯一约束冲突。</p>
|
||||
*/
|
||||
public final class MemberDataFactory {
|
||||
|
||||
private MemberDataFactory() {
|
||||
// 工厂类禁止实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个可正常使用的会员实体。
|
||||
*/
|
||||
public static Member defaultMember() {
|
||||
Long id = TestIds.nextId();
|
||||
Member member = Member.builder()
|
||||
.memberNo(TestIds.nextMemberNo())
|
||||
.nickname("会员-" + id)
|
||||
.phone(TestIds.nextPhone())
|
||||
.gender(1)
|
||||
.birthday(LocalDate.of(1990, 1, 1))
|
||||
.address("测试地址-" + id)
|
||||
.subscribed(false)
|
||||
.lastLoginAt(LocalDateTime.now())
|
||||
.avatar("https://example.com/avatar/" + id + ".png")
|
||||
.unionId(TestIds.nextCode("UNION"))
|
||||
.miniappOpenId(TestIds.nextCode("MINI"))
|
||||
.officialOpenId(TestIds.nextCode("OFFICIAL"))
|
||||
.isDeleted(false)
|
||||
.build();
|
||||
member.setId(id);
|
||||
member.setCreatedAt(LocalDateTime.now());
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定手机号的会员实体。
|
||||
*/
|
||||
public static Member memberWithPhone(String phone) {
|
||||
Member member = defaultMember();
|
||||
member.setPhone(phone);
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认上架的时长卡会员卡的实体。
|
||||
*/
|
||||
public static MemberCard defaultTimeCard() {
|
||||
Long id = TestIds.nextId();
|
||||
MemberCard card = MemberCard.builder()
|
||||
.memberCardId(id)
|
||||
.memberCardName("月卡-" + id)
|
||||
.memberCardType("TIME_CARD")
|
||||
.memberCardPrice(299.0)
|
||||
.memberCardValidityDays(30)
|
||||
.memberCardTotalTimes(null)
|
||||
.memberCardAmount(null)
|
||||
.memberCardStatus(1)
|
||||
.extraConfig(null)
|
||||
.build();
|
||||
card.setId(id);
|
||||
card.setCreatedAt(LocalDateTime.now());
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认上架的次卡会员卡实体。
|
||||
*/
|
||||
public static MemberCard defaultCountCard() {
|
||||
Long id = TestIds.nextId();
|
||||
MemberCard card = MemberCard.builder()
|
||||
.memberCardId(id)
|
||||
.memberCardName("10 次卡-" + id)
|
||||
.memberCardType("COUNT_CARD")
|
||||
.memberCardPrice(499.0)
|
||||
.memberCardValidityDays(null)
|
||||
.memberCardTotalTimes(10)
|
||||
.memberCardAmount(null)
|
||||
.memberCardStatus(1)
|
||||
.extraConfig(null)
|
||||
.build();
|
||||
card.setId(id);
|
||||
card.setCreatedAt(LocalDateTime.now());
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认上架的储值卡会员卡实体。
|
||||
*/
|
||||
public static MemberCard defaultStoredValueCard() {
|
||||
Long id = TestIds.nextId();
|
||||
MemberCard card = MemberCard.builder()
|
||||
.memberCardId(id)
|
||||
.memberCardName("储值卡-" + id)
|
||||
.memberCardType("STORED_VALUE_CARD")
|
||||
.memberCardPrice(null)
|
||||
.memberCardValidityDays(null)
|
||||
.memberCardTotalTimes(null)
|
||||
.memberCardAmount(1000.0)
|
||||
.memberCardStatus(1)
|
||||
.extraConfig(null)
|
||||
.build();
|
||||
card.setId(id);
|
||||
card.setCreatedAt(LocalDateTime.now());
|
||||
return card;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package cn.novalon.gym.manage.test.datafactory;
|
||||
|
||||
import cn.novalon.gym.manage.common.test.TestIds;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardRecord;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardTransaction;
|
||||
import cn.novalon.gym.manage.member.enums.MemberCardRecordStatus;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 订单相关测试数据工厂。
|
||||
*
|
||||
* <p>当前系统中会员卡购买记录({@link MemberCardRecord})与会员卡交易流水
|
||||
* ({@link MemberCardTransaction})承担“订单”语义,本工厂据此提供默认构造。</p>
|
||||
*/
|
||||
public final class OrderDataFactory {
|
||||
|
||||
private OrderDataFactory() {
|
||||
// 工厂类禁止实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的会员卡购买订单(会员卡记录)。
|
||||
*/
|
||||
public static MemberCardRecord defaultMemberCardRecord() {
|
||||
Long id = TestIds.nextId();
|
||||
MemberCardRecord record = MemberCardRecord.builder()
|
||||
.id(id)
|
||||
.memberCardRecordId(id)
|
||||
.memberId(TestIds.nextId())
|
||||
.memberCardId(TestIds.nextId())
|
||||
.status(MemberCardRecordStatus.ACTIVE)
|
||||
.remainingTimes(10)
|
||||
.remainingAmount(0.0)
|
||||
.expireTime(LocalDateTime.now().plusDays(30))
|
||||
.sourceOrderId(TestIds.nextId())
|
||||
.purchaseTime(LocalDateTime.now())
|
||||
.version(0)
|
||||
.cardComposition(null)
|
||||
.build();
|
||||
record.setCreatedAt(LocalDateTime.now());
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定会员与会员卡的购买订单。
|
||||
*/
|
||||
public static MemberCardRecord memberCardRecordOf(Long memberId, Long memberCardId) {
|
||||
MemberCardRecord record = defaultMemberCardRecord();
|
||||
record.setMemberId(memberId);
|
||||
record.setMemberCardId(memberCardId);
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的会员卡交易流水。
|
||||
*/
|
||||
public static MemberCardTransaction defaultTransaction() {
|
||||
Long id = TestIds.nextId();
|
||||
return MemberCardTransaction.builder()
|
||||
.id(id)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.memberCardRecordId(TestIds.nextId())
|
||||
.memberId(TestIds.nextId())
|
||||
.memberCardId(TestIds.nextId())
|
||||
.operationType("PURCHASE")
|
||||
.changeAmount(10)
|
||||
.changeBalance(0.0)
|
||||
.afterRemainingCount(10)
|
||||
.afterRemainingBalance(0.0)
|
||||
.relatedBizType("MEMBER_CARD")
|
||||
.sourceOrderId(TestIds.nextId())
|
||||
.remark("测试交易-" + id)
|
||||
.isArchived(false)
|
||||
.archivedAt(null)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定会员卡记录与会员的交易流水。
|
||||
*/
|
||||
public static MemberCardTransaction transactionOf(Long memberId, Long memberCardRecordId) {
|
||||
MemberCardTransaction transaction = defaultTransaction();
|
||||
transaction.setMemberId(memberId);
|
||||
transaction.setMemberCardRecordId(memberCardRecordId);
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package cn.novalon.gym.manage.test.datafactory;
|
||||
|
||||
import cn.novalon.gym.manage.common.test.TestIds;
|
||||
import cn.novalon.gym.manage.payment.entity.PaymentOrder;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 支付相关测试数据工厂。
|
||||
*
|
||||
* <p>提供支付订单({@link PaymentOrder})的默认构造与常见状态变体。
|
||||
* 注意:{@link PaymentOrder#isNew()} 以 {@code createdAt} 是否为空判断,
|
||||
* 因此默认构造不设置创建时间,便于在 Repository 测试中模拟新实体。</p>
|
||||
*/
|
||||
public final class PaymentDataFactory {
|
||||
|
||||
private static final DateTimeFormatter REQ_DATE_FMT = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private PaymentDataFactory() {
|
||||
// 工厂类禁止实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个默认的待支付订单。
|
||||
*/
|
||||
public static PaymentOrder defaultUnpaidOrder() {
|
||||
Long id = TestIds.nextId();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return PaymentOrder.builder()
|
||||
.id(id)
|
||||
.orderNo(TestIds.nextOrderNo())
|
||||
.memberId(TestIds.nextId())
|
||||
.orderType("MEMBER_CARD")
|
||||
.goodsDesc("会员卡购买")
|
||||
.transAmt(BigDecimal.valueOf(299))
|
||||
.tradeType("JSAPI")
|
||||
.payStatus("UNPAID")
|
||||
.huifuId("6666000207573586")
|
||||
.reqSeqId(TestIds.nextCode("REQ"))
|
||||
.reqDate(now.format(REQ_DATE_FMT))
|
||||
.hfSeqId(null)
|
||||
.partyOrderId(null)
|
||||
.payInfo(null)
|
||||
.qrCode(null)
|
||||
.payUrl(null)
|
||||
.remark("测试支付订单-" + id)
|
||||
.notifyUrl("http://localhost:8084/api/payment/notify")
|
||||
.payTime(null)
|
||||
.expireTime(now.plusMinutes(30))
|
||||
.errorCode(null)
|
||||
.errorMsg(null)
|
||||
.createdAt(null)
|
||||
.updatedAt(null)
|
||||
.deletedAt(null)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个指定会员的待支付订单。
|
||||
*/
|
||||
public static PaymentOrder unpaidOrderOf(Long memberId) {
|
||||
PaymentOrder order = defaultUnpaidOrder();
|
||||
order.setMemberId(memberId);
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个已支付订单。
|
||||
*/
|
||||
public static PaymentOrder defaultPaidOrder() {
|
||||
PaymentOrder order = defaultUnpaidOrder();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
order.setPayStatus("PAID");
|
||||
order.setHfSeqId(TestIds.nextCode("HF"));
|
||||
order.setPayTime(now);
|
||||
order.setCreatedAt(now);
|
||||
order.setUpdatedAt(now);
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个已关闭订单。
|
||||
*/
|
||||
public static PaymentOrder defaultClosedOrder() {
|
||||
PaymentOrder order = defaultUnpaidOrder();
|
||||
order.setPayStatus("CLOSED");
|
||||
order.setErrorCode("CLOSED");
|
||||
order.setErrorMsg("订单已关闭");
|
||||
return order;
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package cn.novalon.gym.manage.test.datafactory;
|
||||
|
||||
import cn.novalon.gym.manage.common.test.UnitTestBase;
|
||||
import cn.novalon.gym.manage.coach.entity.CoachViolationEntity;
|
||||
import cn.novalon.gym.manage.db.entity.CoachTimeRuleEntity;
|
||||
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseBookingEntity;
|
||||
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseEntity;
|
||||
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseTypeEntity;
|
||||
import cn.novalon.gym.manage.member.entity.Member;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCard;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardRecord;
|
||||
import cn.novalon.gym.manage.member.entity.MemberCardTransaction;
|
||||
import cn.novalon.gym.manage.payment.entity.PaymentOrder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* TestDataFactory 冒烟测试。
|
||||
*
|
||||
* <p>验证所有工厂类可正确构造非空实体,且唯一标识不重复。</p>
|
||||
*/
|
||||
class TestDataFactorySmokeTest extends UnitTestBase {
|
||||
|
||||
@Test
|
||||
void shouldCreateUniqueMembers() {
|
||||
Member m1 = MemberDataFactory.defaultMember();
|
||||
Member m2 = MemberDataFactory.defaultMember();
|
||||
|
||||
assertThat(m1).isNotNull();
|
||||
assertThat(m1.getId()).isNotNull();
|
||||
assertThat(m1.getMemberNo()).isNotBlank();
|
||||
assertThat(m1.getId()).isNotEqualTo(m2.getId());
|
||||
assertThat(m1.getMemberNo()).isNotEqualTo(m2.getMemberNo());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateMemberCards() {
|
||||
MemberCard timeCard = MemberDataFactory.defaultTimeCard();
|
||||
MemberCard countCard = MemberDataFactory.defaultCountCard();
|
||||
MemberCard storedCard = MemberDataFactory.defaultStoredValueCard();
|
||||
|
||||
assertThat(timeCard.getMemberCardType()).isEqualTo("TIME_CARD");
|
||||
assertThat(countCard.getMemberCardType()).isEqualTo("COUNT_CARD");
|
||||
assertThat(storedCard.getMemberCardType()).isEqualTo("STORED_VALUE_CARD");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateCoachEntities() {
|
||||
CoachTimeRuleEntity rule = CoachDataFactory.defaultTimeRule();
|
||||
CoachViolationEntity violation = CoachDataFactory.defaultViolation();
|
||||
|
||||
assertThat(rule.getId()).isNotNull();
|
||||
assertThat(violation.getId()).isNotNull();
|
||||
assertThat(rule.getMinDuration()).isLessThanOrEqualTo(rule.getMaxDuration());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateCourseEntities() {
|
||||
GroupCourseTypeEntity type = CourseDataFactory.defaultCourseType();
|
||||
GroupCourseEntity course = CourseDataFactory.defaultGroupCourse();
|
||||
GroupCourseBookingEntity booking = CourseDataFactory.defaultBooking();
|
||||
|
||||
assertThat(type.getId()).isNotNull();
|
||||
assertThat(course.getId()).isNotNull();
|
||||
assertThat(booking.getId()).isNotNull();
|
||||
assertThat(course.getStartTime()).isBefore(course.getEndTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateOrderEntities() {
|
||||
MemberCardRecord record = OrderDataFactory.defaultMemberCardRecord();
|
||||
MemberCardTransaction transaction = OrderDataFactory.defaultTransaction();
|
||||
|
||||
assertThat(record.getId()).isNotNull();
|
||||
assertThat(record.getStatus()).isNotNull();
|
||||
assertThat(transaction.getId()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreatePaymentOrders() {
|
||||
PaymentOrder unpaid = PaymentDataFactory.defaultUnpaidOrder();
|
||||
PaymentOrder paid = PaymentDataFactory.defaultPaidOrder();
|
||||
|
||||
assertThat(unpaid.getId()).isNotNull();
|
||||
assertThat(unpaid.getOrderNo()).isNotBlank();
|
||||
assertThat(unpaid.isNew()).isTrue();
|
||||
assertThat(paid.isNew()).isFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user