docs: add comprehensive documentation for tiered testing

This commit is contained in:
张翔
2026-03-13 12:03:01 +08:00
parent 6c6e9f002f
commit e56d3f20c1
5 changed files with 3843 additions and 0 deletions
+295
View File
@@ -0,0 +1,295 @@
# 分层测试快速入门指南
## 什么是分层测试?
分层测试是一种测试策略,将测试按照执行时间和重要性分为三个层级:
- **快速层**:5分钟内完成,验证核心功能
- **标准层**:30分钟内完成,验证大部分功能
- **深度层**:可接受较长执行时间,进行全面验证
## 快速开始
### 1. 本地运行测试
#### 运行快速层测试(推荐日常开发使用)
```bash
npm run test:tier:fast
```
#### 运行标准层测试
```bash
npm run test:tier:standard
```
#### 运行深度层测试
```bash
npm run test:tier:deep
```
#### 运行所有层级测试
```bash
npm run test:tier:all
```
### 2. 编写分层测试
#### 快速层测试示例
```typescript
test.describe('API快速测试 @smoke @critical', () => {
test('应该能够获取内容列表', async ({ request }) => {
const response = await request.get('/api/admin/content');
expect(response.status()).toBe(200);
});
});
```
#### 标准层测试示例
```typescript
test.describe('管理后台功能测试 @admin @regression', () => {
test('应该能够创建新闻', async ({ page }) => {
await page.goto('/admin/news');
await page.click('[data-testid="create-news-btn"]');
await page.fill('[data-testid="news-title"]', '测试新闻');
await page.click('[data-testid="save-btn"]');
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
});
});
```
#### 深度层测试示例
```typescript
test.describe('首页视觉回归测试 @visual @regression', () => {
test('桌面端首页应该与基准一致', async ({ page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto('/');
await expect(page).toHaveScreenshot('homepage-desktop.png');
});
});
```
### 3. 使用测试标记
为测试添加标记以便分类和管理:
```typescript
test.describe('测试套件 @smoke @critical', () => {
test('测试用例 @api @regression', async ({ page }) => {
// 测试逻辑
});
});
```
**常用标记:**
- `@smoke` - 冒烟测试
- `@critical` - 关键测试
- `@regression` - 回归测试
- `@visual` - 视觉测试
- `@api` - API测试
- `@mobile` - 移动端测试
## CI/CD集成
项目已配置Woodpecker CI,自动执行分层测试:
### 分支策略
- **main分支**:执行所有层级测试
- **develop分支**:执行快速层和标准层测试
- **其他分支**:仅执行快速层测试
### 工作流程
1. 提交代码到分支
2. Woodpecker CI自动触发
3. 依次执行快速层、标准层、深度层测试
4. 前一层失败则停止后续执行
5. 生成测试报告并上传
6. 发送通知
## 性能优化
### 识别慢速测试
运行性能优化工具:
```bash
cd e2e && node test-optimizer-simple-test.js
```
工具会生成优化报告,包含:
- 慢速测试列表
- 优化建议
- 潜在时间节省
### 优化建议
1. **减少等待时间**
```typescript
// 不推荐
await page.waitForTimeout(5000);
// 推荐
await page.waitForSelector('[data-testid="result"]', { timeout: 5000 });
```
2. **使用data-testid选择器**
```typescript
// 不推荐
await page.click('div > div > button');
// 推荐
await page.click('[data-testid="submit-btn"]');
```
3. **拆分大测试**
```typescript
// 不推荐:单个大测试
test('完整的用户注册流程', async ({ page }) => {
// 100+ 行代码
});
// 推荐:拆分为多个小测试
test.describe('用户注册流程', () => {
test('应该能够填写注册表单', async ({ page }) => {
// 20 行代码
});
test('应该能够提交注册', async ({ page }) => {
// 20 行代码
});
});
```
## 监控和告警
### 测试执行历史
系统自动记录测试执行历史,存储在 `e2e/test-history.json`。
### 告警规则
系统会根据以下规则触发告警:
1. 测试通过率低于80% (Critical)
2. 测试通过率低于90% (High)
3. 测试执行时间超过30分钟 (Medium)
4. 失败测试数量超过10个 (High)
5. 深度层测试存在失败 (Critical)
### 查看告警
告警信息会输出到控制台,并保存在 `test-results/alerts.json`。
## 常见问题
### Q: 测试超时怎么办?
A: 检查以下几点:
1. 是否有不必要的等待时间
2. 选择器是否正确
3. 网络请求是否正常
4. 是否需要增加超时时间
### Q: 测试不稳定怎么办?
A: 采用以下策略:
1. 增加重试次数
2. 使用更稳定的等待策略
3. 检查是否有竞态条件
4. 使用data-testid选择器
### Q: 如何确定测试应该放在哪一层?
A: 根据执行时间和重要性:
- 执行时间<30秒且是关键功能 → 快速层
- 执行时间<60秒 → 标准层
- 执行时间>60秒或需要完整回归 → 深度层
### Q: 如何减少测试执行时间?
A: 采用以下策略:
1. 并行执行测试
2. 减少不必要的等待
3. 优化选择器
4. 拆分大测试
5. 使用mock数据
## 进阶使用
### 自定义测试层级
编辑 `e2e/src/config/test-tiers.ts`
```typescript
export const TEST_TIERS: Record<string, TestTierConfig> = {
fast: {
name: '快速层',
description: '冒烟测试、API测试、基础功能验证',
testMatch: /.*\.smoke\.spec\.ts$|.*\.api\.spec\.ts$/,
timeout: 30000,
retries: 1,
workers: process.env.CI ? 6 : '75%',
fullyParallel: true,
failFast: true,
},
// ... 其他层级
};
```
### 添加自定义告警规则
编辑 `e2e/src/utils/test-monitor.ts`
```typescript
this.alertRules.push({
name: 'custom-alert',
condition: (m) => m.failedTests > 5 && m.tier === 'fast',
severity: 'critical',
message: '快速层测试失败超过5个',
});
```
### 自定义优化规则
编辑 `e2e/src/utils/test-optimizer.ts`
```typescript
this.rules.push({
name: 'custom-rule',
condition: (p) => p.duration > 90000 && p.tier === 'standard',
suggestions: [
'标准层测试不应超过90秒',
'考虑拆分测试或优化执行流程',
],
});
```
## 文档资源
- [测试优化指南](./test-optimization-guide.md) - 详细的优化策略和技巧
- [分层测试最佳实践](./test-tiering-best-practices.md) - 完整的最佳实践指南
- [Playwright文档](https://playwright.dev/) - Playwright官方文档
- [Woodpecker CI文档](https://woodpecker-ci.org/docs/) - Woodpecker CI官方文档
## 获取帮助
如果遇到问题:
1. 查看文档资源
2. 检查测试日志
3. 运行性能优化工具
4. 联系团队成员
## 总结
分层测试系统通过以下方式提高测试效率:
1. **快速反馈**:快速层测试在5分钟内完成
2. **合理分配**:根据重要性分配测试资源
3. **持续优化**:通过历史数据持续优化
4. **自动化**CI/CD自动执行和报告
开始使用分层测试,提高测试效率,缩短反馈周期!
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+310
View File
@@ -0,0 +1,310 @@
# 分层测试优化指南
## 概述
本文档介绍如何使用分层测试系统来优化测试执行效率,缩短测试时间,提高测试质量。
## 测试层级
### 快速层 (Fast Tier)
**特点:**
- 执行时间:30秒内
- 测试类型:冒烟测试、API测试、基础功能验证
- 并行度:高(75% workers
- 失败策略:快速失败(failFast: true
- 重试次数:1次
**适用场景:**
- 每次代码提交后的快速验证
- 持续集成(CI)中的第一道防线
- 关键路径的功能验证
**示例:**
```typescript
test.describe('API快速测试 @smoke @critical', () => {
test('应该能够获取内容列表', async ({ request }) => {
const response = await request.get('/api/admin/content');
expect(response.status()).toBe(200);
});
});
```
### 标准层 (Standard Tier)
**特点:**
- 执行时间:60秒内
- 测试类型:功能测试、响应式测试、移动端核心功能
- 并行度:中(50% workers
- 失败策略:继续执行(failFast: false
- 重试次数:2次
**适用场景:**
- 功能分支合并前的验证
- 回归测试的主要部分
- 跨浏览器/设备测试
**示例:**
```typescript
test.describe('管理后台功能测试 @admin @regression', () => {
test('应该能够创建和编辑新闻', async ({ page }) => {
await page.goto('/admin/news');
await page.click('[data-testid="create-news-btn"]');
// ... 测试逻辑
});
});
```
### 深度层 (Deep Tier)
**特点:**
- 执行时间:120秒内
- 测试类型:视觉回归、性能测试、完整回归测试
- 并行度:低(25% workers
- 失败策略:继续执行(failFast: false
- 重试次数:3次
**适用场景:**
- 发布前的完整验证
- 夜间/周末的全面回归
- 性能和视觉质量检查
**示例:**
```typescript
test.describe('首页视觉回归测试 @visual @regression', () => {
test('首页应该与基准截图一致', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png');
});
});
```
## 使用方法
### 本地开发
#### 运行快速层测试
```bash
npm run test:tier:fast
```
#### 运行标准层测试
```bash
npm run test:tier:standard
```
#### 运行深度层测试
```bash
npm run test:tier:deep
```
#### 运行所有层级测试
```bash
npm run test:tier:all
```
### CI/CD集成
#### Woodpecker CI配置
项目已配置Woodpecker CI工作流,支持分层测试自动化执行:
1. **完整工作流** (`.woodpecker/test-tiered.yml`)
- 依次执行快速层、标准层、深度层
- 前一层失败则停止后续执行
- 生成测试报告并上传
- 发送通知
2. **简化工作流** (`.woodpecker/test-tiered-simple.yml`)
- 根据分支类型执行不同层级
- main分支:执行所有层级
- develop分支:执行快速层和标准层
- 其他分支:仅执行快速层
### 测试标记
使用测试标记来分类和管理测试:
```typescript
test.describe('测试套件 @smoke @critical', () => {
test('测试用例 @api @regression', async ({ page }) => {
// 测试逻辑
});
});
```
**可用标记:**
- `@smoke` - 冒烟测试
- `@critical` - 关键测试
- `@regression` - 回归测试
- `@visual` - 视觉测试
- `@performance` - 性能测试
- `@api` - API测试
- `@mobile` - 移动端测试
- `@responsive` - 响应式测试
- `@admin` - 管理后台测试
- `@a11y` - 可访问性测试
- `@security` - 安全测试
## 性能优化
### 识别慢速测试
使用性能优化工具分析测试执行时间:
```bash
cd e2e && node test-optimizer-simple-test.js
```
工具会生成优化报告,包含:
- 慢速测试列表
- 优化建议
- 潜在时间节省
### 优化建议
#### 1. 减少等待时间
```typescript
// 不推荐
await page.waitForTimeout(5000);
// 推荐
await page.waitForSelector('[data-testid="result"]', { timeout: 5000 });
```
#### 2. 优化选择器
```typescript
// 不推荐
await page.click('div > div > button');
// 推荐
await page.click('[data-testid="submit-btn"]');
```
#### 3. 并行测试
```typescript
// playwright.config.tiered.ts
{
fullyParallel: true, // 启用并行执行
workers: '75%', // 使用75%的CPU核心
}
```
#### 4. 测试拆分
```typescript
// 不推荐:单个大测试
test('完整的用户注册流程', async ({ page }) => {
await page.goto('/register');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'password123');
await page.fill('[name="confirm"]', 'password123');
await page.click('[type="submit"]');
await page.waitForURL('/dashboard');
await page.click('[data-testid="profile"]');
// ... 更多步骤
});
// 推荐:拆分为多个小测试
test.describe('用户注册流程', () => {
test('应该能够填写注册表单', async ({ page }) => {
await page.goto('/register');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'password123');
await page.fill('[name="confirm"]', 'password123');
});
test('应该能够提交注册', async ({ page }) => {
await page.goto('/register');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'password123');
await page.fill('[name="confirm"]', 'password123');
await page.click('[type="submit"]');
});
});
```
## 监控和告警
### 测试执行历史
系统会自动记录每次测试执行的历史数据,包括:
- 执行时间
- 成功/失败状态
- 测试标记
历史数据存储在 `e2e/test-history.json`
### 告警规则
系统会根据以下规则触发告警:
1. **测试通过率低于80%** (Critical)
2. **测试通过率低于90%** (High)
3. **测试执行时间超过30分钟** (Medium)
4. **失败测试数量超过10个** (High)
5. **深度层测试存在失败** (Critical)
### 查看告警
告警信息会输出到控制台,并保存在 `test-results/alerts.json`
## 最佳实践
### 1. 测试分层原则
- **快速层**:只包含最关键的测试,确保在5分钟内完成
- **标准层**:包含大部分功能测试,确保在30分钟内完成
- **深度层**:包含完整的回归测试,可以接受较长的执行时间
### 2. 测试标记使用
- 为每个测试套件添加合适的标记
- 优先使用 `@smoke``@critical` 标记关键测试
- 使用 `@regression` 标记需要定期运行的测试
### 3. 持续优化
- 定期运行性能优化工具
- 关注慢速测试的优化
- 根据历史数据调整测试分层
### 4. CI/CD集成
- 在每次提交时运行快速层测试
- 在合并PR时运行标准层测试
- 在发布前运行深度层测试
## 故障排查
### 测试超时
**问题:** 测试执行超时
**解决方案:**
1. 检查是否有不必要的等待
2. 增加测试超时时间
3. 检查网络请求是否正常
### 测试不稳定
**问题:** 测试时好时坏
**解决方案:**
1. 增加重试次数
2. 使用更稳定的等待策略
3. 检查是否有竞态条件
### 执行时间过长
**问题:** 测试执行时间超过预期
**解决方案:**
1. 运行性能优化工具
2. 检查是否有慢速测试
3. 考虑调整测试分层
## 参考资源
- [Playwright文档](https://playwright.dev/)
- [测试金字塔](https://martinfowler.com/articles/practical-test-pyramid.html)
- [Woodpecker CI文档](https://woodpecker-ci.org/docs/)
+450
View File
@@ -0,0 +1,450 @@
# 分层测试最佳实践
## 概述
本文档提供分层测试系统的最佳实践,帮助团队构建高效、可靠的测试体系。
## 核心原则
### 1. 质量左移
在需求分析和设计阶段就考虑测试策略,而不是在开发完成后才补充测试。
**实践:**
- 在需求文档中明确测试要求
- 在设计评审中讨论可测试性
- 开发过程中同步编写测试
### 2. 测试金字塔
遵循测试金字塔原则,保持合理的测试比例:
```
/\
/ \ E2E测试 (10%)
/____\
/ \ 集成测试 (30%)
/________\
/ \ 单元测试 (60%)
/____________\
```
**实践:**
- 单元测试:快速、独立、覆盖核心逻辑
- 集成测试:验证组件间交互
- E2E测试:验证关键用户流程
### 3. 快速反馈
确保测试能够快速提供反馈,帮助开发人员快速定位问题。
**实践:**
- 快速层测试在5分钟内完成
- 标准层测试在30分钟内完成
- 深度层测试可以接受较长执行时间
## 测试分层策略
### 快速层设计
**目标:** 在5分钟内验证核心功能
**包含内容:**
1. **冒烟测试** (Smoke Tests)
- 验证应用能够正常启动
- 验证关键页面能够加载
- 验证核心API能够响应
2. **API测试**
- 验证API端点的正确性
- 验证数据格式和结构
- 验证错误处理
3. **基础功能测试**
- 验证用户登录/登出
- 验证基本CRUD操作
- 验证权限控制
**最佳实践:**
- 每个测试文件不超过3个测试用例
- 每个测试用例执行时间不超过10秒
- 使用mock数据替代真实数据库
**示例:**
```typescript
test.describe('用户认证快速测试 @smoke @critical', () => {
test('应该能够成功登录', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', 'admin@example.com');
await page.fill('[data-testid="password"]', 'password123');
await page.click('[data-testid="login-btn"]');
await expect(page).toHaveURL('/dashboard');
});
test('应该能够成功登出', async ({ page }) => {
await page.goto('/dashboard');
await page.click('[data-testid="logout-btn"]');
await expect(page).toHaveURL('/login');
});
});
```
### 标准层设计
**目标:** 在30分钟内验证大部分功能
**包含内容:**
1. **功能测试** (Functional Tests)
- 验证完整的用户流程
- 验证表单验证
- 验证业务规则
2. **响应式测试** (Responsive Tests)
- 验证不同屏幕尺寸下的布局
- 验证移动端和桌面端的交互
- 验证触摸和鼠标事件
3. **管理后台测试** (Admin Tests)
- 验证内容管理功能
- 验证用户管理功能
- 验证系统配置
**最佳实践:**
- 每个测试文件包含5-10个测试用例
- 每个测试用例执行时间不超过30秒
- 使用Page Object Model模式
**示例:**
```typescript
test.describe('新闻管理功能测试 @admin @regression', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/admin/news');
});
test('应该能够创建新闻', async ({ page }) => {
await page.click('[data-testid="create-news-btn"]');
await page.fill('[data-testid="news-title"]', '测试新闻');
await page.fill('[data-testid="news-content"]', '新闻内容');
await page.click('[data-testid="save-btn"]');
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
});
test('应该能够编辑新闻', async ({ page }) => {
await page.click('[data-testid="edit-news-1"]');
await page.fill('[data-testid="news-title"]', '更新后的标题');
await page.click('[data-testid="save-btn"]');
await expect(page.locator('[data-testid="news-title"]')).toHaveValue('更新后的标题');
});
test('应该能够删除新闻', async ({ page }) => {
await page.click('[data-testid="delete-news-1"]');
await page.click('[data-testid="confirm-btn"]');
await expect(page.locator('[data-testid="news-1"]')).not.toBeVisible();
});
});
```
### 深度层设计
**目标:** 在发布前进行全面验证
**包含内容:**
1. **视觉回归测试** (Visual Regression Tests)
- 验证UI与设计稿一致
- 验证样式和布局
- 验证跨浏览器一致性
2. **性能测试** (Performance Tests)
- 验证页面加载时间
- 验证API响应时间
- 验证资源加载优化
3. **完整回归测试** (Full Regression Tests)
- 验证所有已知功能
- 验证边界情况
- 验证错误处理
**最佳实践:**
- 使用截图对比工具
- 使用性能监控工具
- 在夜间或周末执行
**示例:**
```typescript
test.describe('首页视觉回归测试 @visual @regression', () => {
test('桌面端首页应该与基准一致', async ({ page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await page.goto('/');
await expect(page).toHaveScreenshot('homepage-desktop.png');
});
test('移动端首页应该与基准一致', async ({ page }) => {
await page.setViewportSize({ width: 375, height: 667 });
await page.goto('/');
await expect(page).toHaveScreenshot('homepage-mobile.png');
});
});
```
## 测试标记策略
### 标记分类
#### 优先级标记
- `@critical` - 关键测试,必须通过
- `@high` - 高优先级测试
- `@medium` - 中等优先级测试
- `@low` - 低优先级测试
#### 类型标记
- `@smoke` - 冒烟测试
- `@regression` - 回归测试
- `@functional` - 功能测试
- `@api` - API测试
- `@visual` - 视觉测试
- `@performance` - 性能测试
#### 平台标记
- `@desktop` - 桌面端测试
- `@mobile` - 移动端测试
- `@tablet` - 平板端测试
#### 功能标记
- `@auth` - 认证相关测试
- `@admin` - 管理后台测试
- `@content` - 内容管理测试
- `@user` - 用户功能测试
### 标记使用规则
1. **每个测试套件至少有一个标记**
2. **关键测试必须标记为 `@critical`**
3. **冒烟测试必须标记为 `@smoke`**
4. **回归测试必须标记为 `@regression`**
## 性能优化
### 减少测试执行时间
#### 1. 并行执行
```typescript
// playwright.config.tiered.ts
{
fullyParallel: true,
workers: '75%',
}
```
#### 2. 减少等待时间
```typescript
// 不推荐
await page.waitForTimeout(5000);
// 推荐
await page.waitForSelector('[data-testid="result"]', { timeout: 5000 });
```
#### 3. 使用快速选择器
```typescript
// 不推荐
await page.click('div > div > button');
// 推荐
await page.click('[data-testid="submit-btn"]');
```
#### 4. 复用浏览器上下文
```typescript
test.describe('用户管理测试', () => {
test.use({ storageState: '.auth/admin.json' });
test('应该能够创建用户', async ({ page }) => {
// 测试逻辑
});
});
```
### 优化测试数据
#### 1. 使用固定数据
```typescript
const testUser = {
email: 'test@example.com',
password: 'password123',
};
test('应该能够登录', async ({ page }) => {
await page.fill('[data-testid="email"]', testUser.email);
await page.fill('[data-testid="password"]', testUser.password);
});
```
#### 2. 使用测试数据库
```typescript
test.beforeEach(async () => {
await db.reset();
await db.seed(testData);
});
```
#### 3. 清理测试数据
```typescript
test.afterEach(async () => {
await db.cleanup();
});
```
## 可维护性
### Page Object Model
使用Page Object Model模式提高测试的可维护性:
```typescript
// pages/LoginPage.ts
export class LoginPage {
constructor(private page: Page) {}
async login(email: string, password: string) {
await this.page.fill('[data-testid="email"]', email);
await this.page.fill('[data-testid="password"]', password);
await this.page.click('[data-testid="login-btn"]');
}
async expectLoggedIn() {
await expect(this.page).toHaveURL('/dashboard');
}
}
// tests/login.spec.ts
test('应该能够登录', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login('admin@example.com', 'password123');
await loginPage.expectLoggedIn();
});
```
### 测试数据管理
使用专门的测试数据管理器:
```typescript
// utils/test-data.ts
export const TestData = {
users: {
admin: {
email: 'admin@example.com',
password: 'password123',
role: 'admin',
},
user: {
email: 'user@example.com',
password: 'password123',
role: 'user',
},
},
news: {
valid: {
title: '测试新闻',
content: '新闻内容',
},
invalid: {
title: '',
content: '',
},
},
};
```
### 配置管理
使用环境变量管理测试配置:
```typescript
// config/environments.ts
export const getEnvironment = () => {
const env = process.env.NODE_ENV || 'development';
return {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
timeout: parseInt(process.env.TEST_TIMEOUT || '30000'),
retries: parseInt(process.env.TEST_RETRIES || '2'),
headless: process.env.HEADLESS !== 'false',
};
};
```
## 持续改进
### 定期审查
每月进行一次测试审查:
1. 检查测试覆盖率
2. 识别慢速测试
3. 评估测试有效性
4. 清理无用测试
### 性能监控
持续监控测试性能:
1. 记录测试执行时间
2. 识别性能趋势
3. 优化慢速测试
4. 调整测试分层
### 反馈收集
收集测试反馈:
1. 开发人员反馈
2. 测试失败分析
3. 用户反馈
4. 生产问题追踪
## 常见问题
### Q: 如何确定测试应该放在哪一层?
A: 根据测试的执行时间和重要性:
- 执行时间<30秒且是关键功能 → 快速层
- 执行时间<60秒 → 标准层
- 执行时间>60秒或需要完整回归 → 深度层
### Q: 测试失败时如何处理?
A: 按照以下优先级处理:
1. 快速层测试失败 → 立即修复
2. 标准层测试失败 → 在合并PR前修复
3. 深度层测试失败 → 在发布前修复
### Q: 如何减少测试执行时间?
A: 采用以下策略:
1. 并行执行测试
2. 减少不必要的等待
3. 优化选择器
4. 拆分大测试
5. 使用mock数据
### Q: 如何提高测试稳定性?
A: 遵循以下原则:
1. 使用稳定的等待策略
2. 避免硬编码的等待时间
3. 使用data-testid选择器
4. 清理测试数据
5. 增加重试次数
## 参考资源
- [Playwright最佳实践](https://playwright.dev/docs/best-practices)
- [测试金字塔](https://martinfowler.com/articles/practical-test-pyramid.html)
- [Page Object Model](https://playwright.dev/docs/pom)
- [测试驱动开发](https://martinfowler.com/bliki/TestDrivenDevelopment.html)