diff --git a/docs/superpowers/specs/2026-04-09-test-quality-improvement-design.md b/docs/superpowers/specs/2026-04-09-test-quality-improvement-design.md new file mode 100644 index 0000000..3bf0697 --- /dev/null +++ b/docs/superpowers/specs/2026-04-09-test-quality-improvement-design.md @@ -0,0 +1,737 @@ +# 测试质量完善设计文档 + +**日期:** 2026-04-09 +**版本:** 1.0 +**状态:** 待审查 + +--- + +## 一、背景与目标 + +### 1.1 项目现状 + +**已完成工作:** +- ✅ 企业官网核心功能(首页、服务、产品、案例、新闻、联系) +- ✅ CMS管理后台(内容管理、用户管理) +- ✅ 测试架构重构(Page Object Model、测试固件、分层测试) +- ✅ 冒烟测试全部通过(8/8) +- ✅ CI/CD流水线配置 + +**待优化工作:** +- ⚠️ 用户旅程测试(3/12通过) +- ⚠️ 功能测试(待验证) +- ⚠️ 测试覆盖率不足 +- ⚠️ 缺乏测试规范和工具支持 + +### 1.2 核心目标 + +**总体目标:** 在1-2周内全面完善测试质量,建立稳定、高效、可维护的测试体系 + +**关键指标:** +- ✅ 所有测试通过率:100% +- ✅ 代码覆盖率:单元测试70%+、集成测试20%+、E2E测试10% +- ✅ 测试执行速度:快速层<2分钟、标准层<10分钟、深度层<30分钟 +- ✅ CI/CD稳定性:连续10次构建无失败 + +--- + +## 二、实施策略 + +### 2.1 实施方案:测试优先 + +**选择理由:** +1. 快速反馈 - 立即修复失败的测试,让CI/CD流水线恢复健康 +2. 渐进式学习 - 在修复测试过程中深入理解代码和痛点 +3. 降低风险 - 先让现有测试工作起来,再考虑扩展 +4. 符合实际 - 当前已有测试架构基础,优先修复比从零建立更实际 + +### 2.2 时间规划 + +**总时长:** 7天(1周) + +**阶段划分:** +- 第1-2天:修复现有测试 +- 第3-5天:补充测试覆盖 +- 第6-7天:建立基础设施 + +--- + +## 三、详细实施计划 + +### 3.1 第1-2天:修复现有测试 + +#### 目标 +让所有现有测试通过,恢复CI/CD流水线健康 + +#### 任务清单 + +**第1天:修复用户旅程测试** + +1. **修复页面加载超时问题** + - 为所有 `page.goto()` 添加 `{ waitUntil: 'domcontentloaded' }` 选项 + - 增加断言超时时间到10秒 + - 优化页面等待策略 + +2. **修复元素定位问题** + - 使用 `getByRole()` 替代 `locator()` 避免严格模式冲突 + - 使用更精确的选择器(如 `getByTestId()`) + - 处理动态元素和异步加载 + +3. **优化测试数据管理** + - 确保测试数据唯一性(使用时间戳) + - 添加测试数据清理逻辑 + - 验证测试固件正确性 + +**第2天:修复功能测试和验证稳定性** + +1. **修复功能测试** + - 验证内容管理测试(CRUD操作) + - 验证用户管理测试 + - 验证前端响应式和无障碍测试 + +2. **验证测试稳定性** + - 本地运行所有测试3次,确保100%通过 + - 修复偶发性失败(flaky tests) + - 优化测试执行顺序 + +#### 交付物 +- ✅ 所有测试通过(40/40) +- ✅ 测试执行报告 +- ✅ 问题修复记录文档 + +--- + +### 3.2 第3-5天:补充测试覆盖 + +#### 目标 +达到分层覆盖率目标:单元测试70%+、集成测试20%+、E2E测试10% + +#### 任务清单 + +**第3天:单元测试(目标70%+)** + +1. **核心业务逻辑单元测试** + - 内容管理服务(ContentService) + - 用户管理服务(UserService) + - 邮件服务(EmailService) + - 文件上传服务(FileService) + +2. **工具函数单元测试** + - 数据验证工具(validation.ts) + - 格式化工具(format.ts) + - 加密工具(crypto.ts) + - 日期处理工具(date.ts) + +3. **组件单元测试** + - UI组件(Button、Input、Modal等) + - 表单组件(ContactForm、ContentForm等) + - 布局组件(Header、Footer、Navigation等) + +**第4天:集成测试(目标20%+)** + +1. **API集成测试** + - 内容管理API(/api/content/*) + - 用户管理API(/api/users/*) + - 认证API(/api/auth/*) + - 文件上传API(/api/upload/*) + +2. **数据库集成测试** + - Drizzle ORM查询测试 + - 数据库事务测试 + - 数据库迁移测试 + +3. **组件集成测试** + - 表单提交流程 + - 数据展示流程 + - 用户交互流程 + +**第5天:E2E测试(目标10%+)** + +1. **完善用户旅程测试** + - 访客浏览旅程(已修复) + - 用户认证旅程(已修复) + - 管理员内容发布旅程(已修复) + +2. **添加关键业务流程测试** + - 内容发布完整流程 + - 用户注册登录流程 + - 联系表单提交流程 + +3. **添加异常场景测试** + - 网络错误处理 + - 表单验证错误 + - 权限不足场景 + +#### 交付物 +- ✅ 覆盖率报告(单元70%+、集成20%+、E2E 10%) +- ✅ 新增测试用例清单 +- ✅ 测试覆盖率趋势图 + +--- + +### 3.3 第6-7天:建立基础设施 + +#### 目标 +建立完整的测试可维护性体系 + +#### 任务清单 + +**第6天:规范和文档** + +1. **编写测试规范** + - 测试命名约定 + ```typescript + // 单元测试:[模块名].test.ts + // 集成测试:[模块名].integration.test.ts + // E2E测试:[功能名].spec.ts + + // 测试用例命名:should_[期望行为]_when_[条件] + test('should_return_user_when_valid_id_provided', () => { + // ... + }); + ``` + + - 测试文件结构 + ``` + tests/ + ├── unit/ # 单元测试 + ├── integration/ # 集成测试 + └── e2e/ # E2E测试 + ├── smoke/ # 冒烟测试 + ├── journeys/ # 用户旅程测试 + └── features/ # 功能测试 + ``` + + - 测试数据管理规范 + - 使用测试固件工厂模式 + - 测试数据隔离 + - 自动清理机制 + + - 断言最佳实践 + - 使用语义化断言 + - 避免多重断言 + - 清晰的错误消息 + +2. **编写测试指南** + - 单元测试编写指南 + - Jest配置和最佳实践 + - Mock和Stub使用 + - 测试覆盖率要求 + + - 集成测试编写指南 + - 测试环境配置 + - 数据库测试策略 + - API测试策略 + + - E2E测试编写指南 + - Playwright配置和最佳实践 + - Page Object Model使用 + - 测试固件使用 + + - 测试调试技巧 + - 常见问题排查 + - 调试工具使用 + - 性能优化技巧 + +**第7天:工具和CI/CD** + +1. **创建测试脚手架工具** + + - 单元测试生成器 + ```bash + npm run test:generate:unit -- --name UserService + # 生成: tests/unit/services/UserService.test.ts + ``` + + - Page Object生成器 + ```bash + npm run test:generate:page -- --name AdminDashboard + # 生成: e2e/pages/AdminDashboardPage.ts + ``` + + - 测试数据生成器 + ```bash + npm run test:generate:data -- --type user + # 生成: tests/fixtures/users.ts + ``` + +2. **配置CI/CD质量门禁** + + - 快速层:每次提交运行 + ```yaml + # 触发条件:每次push + # 运行内容:冒烟测试 + # 超时时间:5分钟 + # 失败策略:阻止合并 + ``` + + - 标准层:每次PR运行 + ```yaml + # 触发条件:PR创建/更新 + # 运行内容:核心功能测试 + # 超时时间:15分钟 + # 失败策略:阻止合并 + ``` + + - 深度层:合并到主分支运行 + ```yaml + # 触发条件:合并到main + # 运行内容:完整测试套件 + # 超时时间:45分钟 + # 失败策略:通知团队 + ``` + +3. **建立测试监控** + - 测试覆盖率趋势监控 + - 每日覆盖率报告 + - 覆盖率下降告警 + - 覆盖率趋势图 + + - 测试失败告警 + - 实时失败通知 + - 失败原因分析 + - 历史失败统计 + + - 测试性能监控 + - 测试执行时间趋势 + - 慢测试识别 + - 性能优化建议 + +#### 交付物 +- ✅ 测试规范文档(`docs/testing/standards.md`) +- ✅ 测试指南文档(`docs/testing/guide.md`) +- ✅ 测试脚手架工具(`scripts/test-generators/`) +- ✅ CI/CD配置更新(`.github/workflows/test.yml`) +- ✅ 测试监控面板(`docs/testing/monitoring.md`) + +--- + +## 四、技术方案 + +### 4.1 测试分层架构 + +``` +测试金字塔 + /\ + / \ E2E测试 (10%) + /----\ + / \ 集成测试 (20%) +/--------\ +/ \ 单元测试 (70%) +/----------\ +``` + +**分层策略:** + +| 层级 | 测试类型 | 数量 | 执行时间 | 触发条件 | 覆盖率目标 | +|------|---------|------|---------|---------|-----------| +| 快速层 | 冒烟测试 | 8个 | <2分钟 | 每次提交 | 核心功能 | +| 标准层 | 核心功能测试 | 30个 | <10分钟 | 每次PR | 主要业务流程 | +| 深度层 | 完整套件 | 40个 | <30分钟 | 合并到main | 全面覆盖 | + +### 4.2 测试数据管理 + +**方案:** 使用测试固件工厂模式 + +```typescript +// tests/fixtures/factory.ts +import { faker } from '@faker-js/faker'; + +export const TestDataFactory = { + createUser: (overrides?: Partial) => ({ + id: faker.string.uuid(), + email: faker.internet.email(), + name: faker.person.fullName(), + role: 'user', + createdAt: new Date(), + ...overrides, + }), + + createContent: (overrides?: Partial) => ({ + id: faker.string.uuid(), + title: faker.lorem.sentence(), + content: faker.lorem.paragraphs(), + type: 'news', + status: 'draft', + authorId: faker.string.uuid(), + createdAt: new Date(), + ...overrides, + }), + + createAdminUser: () => ({ + email: 'admin@test.com', + password: 'Admin123!@#', + name: 'Test Admin', + role: 'admin', + }), +}; +``` + +**使用示例:** + +```typescript +// 单元测试 +import { TestDataFactory } from '@/tests/fixtures/factory'; + +test('should create user', () => { + const user = TestDataFactory.createUser({ name: 'John' }); + expect(user.name).toBe('John'); +}); + +// E2E测试 +import { testFixtures } from '@/e2e/fixtures/test-data'; + +test('admin login', async ({ page }) => { + const admin = testFixtures.adminUser; + await page.fill('#email', admin.email); + await page.fill('#password', admin.password); +}); +``` + +### 4.3 Page Object Model + +**规范:** + +```typescript +// e2e/pages/BasePage.ts +export abstract class BasePage { + constructor(protected page: Page) {} + + async goto(path: string) { + await this.page.goto(path, { waitUntil: 'domcontentloaded' }); + } + + async waitForLoad() { + await this.page.waitForLoadState('networkidle'); + } +} + +// e2e/pages/AdminContentPage.ts +export class AdminContentPage extends BasePage { + async goto() { + await super.goto('/admin/content'); + } + + async createContent(data: ContentData) { + await this.page.click('button:has-text("新建内容")'); + await this.page.fill('#title', data.title); + await this.page.fill('#content', data.content); + await this.page.click('button[type="submit"]'); + } + + async expectContentInList(title: string) { + await expect(this.page.locator(`text=${title}`)).toBeVisible(); + } +} +``` + +### 4.4 CI/CD质量门禁 + +```yaml +# .github/workflows/test.yml +name: Test Pipeline + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + # 快速层:冒烟测试 + quick-tests: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run smoke tests + run: npm run test:smoke + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: smoke-test-results + path: test-results/ + + # 标准层:核心功能测试 + standard-tests: + runs-on: ubuntu-latest + needs: quick-tests + timeout-minutes: 15 + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run standard tests + run: npm run test:standard + + - name: Upload coverage + uses: codecov/codecov-action@v4 + with: + files: ./coverage/lcov.info + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: standard-test-results + path: test-results/ + + # 深度层:完整测试套件 + deep-tests: + runs-on: ubuntu-latest + needs: standard-tests + timeout-minutes: 45 + if: github.ref == 'refs/heads/main' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run all tests + run: npm run test:deep + + - name: Generate coverage report + run: npm run test:coverage + + - name: Upload coverage + uses: codecov/codecov-action@v4 + with: + files: ./coverage/lcov.info + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: deep-test-results + path: test-results/ +``` + +--- + +## 五、成功标准 + +### 5.1 第1-2天验收标准 + +**测试通过率:** +- ✅ 所有测试通过(40/40) +- ✅ 本地运行3次无失败 +- ✅ CI/CD流水线绿色 + +**测试稳定性:** +- ✅ 无flaky tests +- ✅ 测试执行时间稳定 +- ✅ 测试结果可重复 + +### 5.2 第3-5天验收标准 + +**覆盖率目标:** +- ✅ 单元测试覆盖率 ≥ 70% +- ✅ 集成测试覆盖率 ≥ 20% +- ✅ E2E测试覆盖率 ≥ 10% +- ✅ 总体覆盖率 ≥ 60% + +**测试质量:** +- ✅ 所有新增测试通过 +- ✅ 测试代码符合规范 +- ✅ 测试文档完整 + +### 5.3 第6-7天验收标准 + +**文档完整性:** +- ✅ 测试规范文档完成 +- ✅ 测试指南文档完成 +- ✅ 示例代码完整 + +**工具可用性:** +- ✅ 测试脚手架工具可用 +- ✅ 工具文档完整 +- ✅ 工具测试通过 + +**CI/CD配置:** +- ✅ 质量门禁生效 +- ✅ 测试监控上线 +- ✅ 告警机制正常 + +### 5.4 最终验收标准 + +**稳定性:** +- ✅ 连续10次CI/CD构建成功 +- ✅ 无测试失败 +- ✅ 无性能退化 + +**效率:** +- ✅ 测试执行时间符合预期 +- ✅ 快速层<2分钟 +- ✅ 标准层<10分钟 +- ✅ 深度层<30分钟 + +**可维护性:** +- ✅ 团队能使用工具快速编写测试 +- ✅ 测试文档清晰易懂 +- ✅ 新成员能快速上手 + +--- + +## 六、风险管理 + +### 6.1 风险识别 + +| 风险 | 概率 | 影响 | 风险等级 | +|------|------|------|---------| +| 测试修复时间超出预期 | 中 | 高 | 高 | +| 覆盖率目标难以达成 | 中 | 中 | 中 | +| 工具开发时间不足 | 低 | 中 | 低 | +| 团队成员不熟悉新规范 | 中 | 中 | 中 | +| CI/CD配置复杂 | 低 | 高 | 中 | + +### 6.2 缓解措施 + +**风险1:测试修复时间超出预期** +- **缓解措施:** 优先修复高优先级测试,低优先级测试可延后 +- **应急方案:** 调整时间计划,增加1天缓冲时间 +- **责任人:** 测试负责人 + +**风险2:覆盖率目标难以达成** +- **缓解措施:** 聚焦核心业务逻辑,非关键代码可适当降低要求 +- **应急方案:** 调整覆盖率目标,单元测试降至60% +- **责任人:** 开发负责人 + +**风险3:工具开发时间不足** +- **缓解措施:** 先提供基础功能,后续迭代完善 +- **应急方案:** 手动创建测试,工具延后开发 +- **责任人:** 工具开发负责人 + +**风险4:团队成员不熟悉新规范** +- **缓解措施:** 提供详细文档和示例,安排培训时间 +- **应急方案:** 一对一辅导,逐步推广 +- **责任人:** 团队负责人 + +**风险5:CI/CD配置复杂** +- **缓解措施:** 参考成熟项目配置,逐步调试 +- **应急方案:** 简化配置,分阶段实施 +- **责任人:** DevOps负责人 + +--- + +## 七、后续演进 + +### 7.1 短期优化(1个月内) + +1. **测试性能优化** + - 优化测试执行速度 + - 减少测试资源消耗 + - 提升测试稳定性 + +2. **工具功能增强** + - 增加测试生成器功能 + - 优化测试报告展示 + - 增加测试调试工具 + +3. **文档持续完善** + - 根据反馈更新文档 + - 增加更多示例 + - 制作视频教程 + +### 7.2 中期规划(3个月内) + +1. **测试智能化** + - 引入AI辅助测试生成 + - 自动化测试数据生成 + - 智能测试推荐 + +2. **测试可视化** + - 测试覆盖率可视化 + - 测试执行趋势分析 + - 测试质量评分 + +3. **测试治理** + - 测试代码质量检查 + - 测试债务管理 + - 测试重构计划 + +### 7.3 长期愿景(6个月内) + +1. **测试平台化** + - 统一测试管理平台 + - 测试资产沉淀 + - 测试知识库建设 + +2. **测试标准化** + - 建立测试标准体系 + - 测试最佳实践库 + - 测试培训体系 + +3. **测试文化** + - 测试驱动开发文化 + - 质量意识提升 + - 持续改进机制 + +--- + +## 八、附录 + +### 8.1 参考资源 + +**测试框架文档:** +- [Jest官方文档](https://jestjs.io/) +- [Playwright官方文档](https://playwright.dev/) +- [Testing Library文档](https://testing-library.com/) + +**最佳实践:** +- [Google Testing Blog](https://testing.googleblog.com/) +- [Martin Fowler - Testing](https://martinfowler.com/testing/) +- [Test Pyramid](https://martinfowler.com/articles/practical-test-pyramid.html) + +**工具和库:** +- [@faker-js/faker](https://fakerjs.dev/) +- [MSW - Mock Service Worker](https://mswjs.io/) +- [Codecov](https://codecov.io/) + +### 8.2 术语表 + +| 术语 | 定义 | +|------|------| +| 单元测试 | 测试单个函数或组件的测试 | +| 集成测试 | 测试多个模块集成的测试 | +| E2E测试 | 端到端测试,模拟用户真实操作 | +| 冒烟测试 | 快速验证核心功能的测试 | +| 测试覆盖率 | 代码被测试覆盖的比例 | +| Flaky Test | 偶发性失败的测试 | +| Page Object Model | 页面对象模型,封装页面操作 | +| 测试固件 | 测试数据和环境的固定配置 | + +### 8.3 联系方式 + +**项目负责人:** 张翔 +**技术支持:** 开发团队 +**问题反馈:** 项目Issue跟踪系统 + +--- + +**文档版本历史:** + +| 版本 | 日期 | 作者 | 变更说明 | +|------|------|------|---------| +| 1.0 | 2026-04-09 | 张翔 | 初始版本 |