08ea5fbe98
添加用户管理视图、API和状态管理文件
546 lines
12 KiB
Markdown
546 lines
12 KiB
Markdown
# E2E测试框架使用文档
|
||
|
||
## 目录
|
||
|
||
- [概述](#概述)
|
||
- [快速开始](#快速开始)
|
||
- [项目结构](#项目结构)
|
||
- [核心功能](#核心功能)
|
||
- [编写测试](#编写测试)
|
||
- [运行测试](#运行测试)
|
||
- [CI/CD集成](#cicd集成)
|
||
- [最佳实践](#最佳实践)
|
||
- [故障排查](#故障排查)
|
||
|
||
## 概述
|
||
|
||
本E2E测试框架基于Playwright构建,为uniapp和admin模块提供完整的端到端测试解决方案。框架采用模块化设计,支持前后端完全联通的测试场景,确保业务流程的完整性和正确性。
|
||
|
||
### 主要特性
|
||
|
||
- ✅ 基于Playwright的现代化E2E测试框架
|
||
- ✅ 支持uniapp和admin模块的全流程业务测试
|
||
- ✅ 完整的测试数据管理和清理机制
|
||
- ✅ 丰富的测试辅助工具(表单、表格、断言等)
|
||
- ✅ 详细的测试日志和截图功能
|
||
- ✅ 多种测试报告格式(HTML、JSON、JUnit)
|
||
- ✅ 完整的CI/CD集成支持
|
||
- ✅ 支持多浏览器和多设备测试
|
||
|
||
## 快速开始
|
||
|
||
### 环境要求
|
||
|
||
- Node.js >= 18.0.0
|
||
- npm >= 9.0.0
|
||
- Docker(用于运行测试环境)
|
||
|
||
### 安装依赖
|
||
|
||
```bash
|
||
cd everything-is-suitable-test
|
||
npm install
|
||
```
|
||
|
||
### 安装Playwright浏览器
|
||
|
||
```bash
|
||
npm run test:install
|
||
```
|
||
|
||
### 配置环境变量
|
||
|
||
复制环境变量示例文件:
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
编辑`.env`文件,配置测试环境:
|
||
|
||
```env
|
||
TEST_ENV=local
|
||
ADMIN_BASE_URL=http://localhost:5174
|
||
UNIAPP_BASE_URL=http://localhost:8081
|
||
API_BASE_URL=http://127.0.0.1:8080
|
||
TEST_USERNAME=admin
|
||
TEST_PASSWORD=admin123
|
||
MOCK_ENABLED=false
|
||
TEST_TIMEOUT=30000
|
||
```
|
||
|
||
### 运行测试
|
||
|
||
```bash
|
||
npm run test
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
everything-is-suitable-test/
|
||
├── e2e/
|
||
│ ├── fixtures/ # 测试夹具
|
||
│ │ └── test-fixtures.ts # 自定义测试夹具
|
||
│ ├── core/ # 核心模块
|
||
│ │ ├── test-config.ts # 测试配置管理
|
||
│ │ ├── test-logger.ts # 测试日志记录
|
||
│ │ ├── test-reporter.ts # 测试报告生成
|
||
│ │ └── test-data-manager.ts # 测试数据管理
|
||
│ ├── helpers/ # 测试辅助工具
|
||
│ │ ├── api-helper.ts # API请求辅助
|
||
│ │ ├── form-helper.ts # 表单操作辅助
|
||
│ │ ├── table-helper.ts # 表格操作辅助
|
||
│ │ ├── screenshot-helper.ts # 截图辅助
|
||
│ │ └── assertion-helper.ts # 断言辅助
|
||
│ └── examples/ # 示例测试
|
||
│ ├── user-management.spec.ts
|
||
│ ├── api-integration.spec.ts
|
||
│ ├── uniapp-almanac.spec.ts
|
||
│ ├── uniapp-user.spec.ts
|
||
│ ├── admin-user-management.spec.ts
|
||
│ └── admin-role-management.spec.ts
|
||
├── playwright.config.ts # Playwright配置
|
||
├── package.json
|
||
├── tsconfig.json
|
||
└── .env.example
|
||
```
|
||
|
||
## 核心功能
|
||
|
||
### 测试夹具 (Fixtures)
|
||
|
||
框架提供了一组自定义测试夹具,可以在测试中直接使用:
|
||
|
||
```typescript
|
||
test('示例测试', async ({
|
||
page,
|
||
testConfig,
|
||
testLogger,
|
||
testDataManager,
|
||
apiHelper,
|
||
formHelper,
|
||
tableHelper,
|
||
screenshotHelper,
|
||
assertionHelper
|
||
}) => {
|
||
// 使用夹具进行测试
|
||
});
|
||
```
|
||
|
||
#### 可用夹具
|
||
|
||
| 夹具名称 | 描述 |
|
||
|---------|------|
|
||
| `testConfig` | 测试配置管理 |
|
||
| `testLogger` | 测试日志记录 |
|
||
| `testReporter` | 测试报告生成 |
|
||
| `testDataManager` | 测试数据管理 |
|
||
| `apiHelper` | API请求辅助 |
|
||
| `formHelper` | 表单操作辅助 |
|
||
| `tableHelper` | 表格操作辅助 |
|
||
| `screenshotHelper` | 截图辅助 |
|
||
| `assertionHelper` | 断言辅助 |
|
||
|
||
### 测试数据管理
|
||
|
||
`TestDataManager`提供完整的测试数据生命周期管理:
|
||
|
||
```typescript
|
||
const testUser = await testDataManager.createTestUser({
|
||
realName: '测试用户',
|
||
email: 'test@example.com'
|
||
});
|
||
|
||
// 测试完成后自动清理
|
||
```
|
||
|
||
### 测试辅助工具
|
||
|
||
#### APIHelper
|
||
|
||
```typescript
|
||
await apiHelper.login('admin', 'admin123');
|
||
const response = await apiHelper.get('/api/sys/user');
|
||
await apiHelper.post('/api/sys/user', userData);
|
||
await apiHelper.put('/api/sys/user', updateData);
|
||
await apiHelper.delete(`/api/sys/user/${userId}`);
|
||
```
|
||
|
||
#### FormHelper
|
||
|
||
```typescript
|
||
await formHelper.fillField('input[name="username"]', 'testuser');
|
||
await formHelper.fillForm({
|
||
'input[name="username"]': { value: 'testuser' },
|
||
'input[name="password"]': { value: 'password123' }
|
||
});
|
||
await formHelper.submitForm('button[type="submit"]');
|
||
```
|
||
|
||
#### TableHelper
|
||
|
||
```typescript
|
||
const rowCount = await tableHelper.getRowCount('.user-table');
|
||
const cellText = await tableHelper.getCellText('.user-table', 1, 2);
|
||
const matchingRows = await tableHelper.findRowsByCellText('.user-table', 'testuser');
|
||
await tableHelper.clickRow('.user-table', 1);
|
||
```
|
||
|
||
#### AssertionHelper
|
||
|
||
```typescript
|
||
await assertionHelper.assertElementVisible(page, '.user-table');
|
||
await assertionHelper.assertElementText(page, '.user-name', '张三');
|
||
await assertionHelper.assertSuccessMessage(page);
|
||
await assertionHelper.assertAPISuccess(response);
|
||
```
|
||
|
||
#### ScreenshotHelper
|
||
|
||
```typescript
|
||
await screenshotHelper.takeScreenshot('test-name');
|
||
await screenshotHelper.takeElementScreenshot('.element', 'element-name');
|
||
await screenshotHelper.takeScreenshotOnFailure('test-name');
|
||
await screenshotHelper.takeScreenshotOnSuccess('test-name');
|
||
```
|
||
|
||
## 编写测试
|
||
|
||
### 基本测试结构
|
||
|
||
```typescript
|
||
import { test, expect } from './fixtures/test-fixtures';
|
||
|
||
test.describe('功能模块测试', () => {
|
||
test.beforeEach(async ({ page, testConfig, testLogger }) => {
|
||
testLogger.startTest('功能模块测试');
|
||
await page.goto(testConfig.getEnvironment().baseURL);
|
||
});
|
||
|
||
test.afterEach(async ({ testLogger }) => {
|
||
testLogger.endTest('功能模块测试', 'passed');
|
||
});
|
||
|
||
test('TC-001: 测试用例名称', async ({
|
||
page,
|
||
formHelper,
|
||
assertionHelper,
|
||
testLogger,
|
||
screenshotHelper
|
||
}) => {
|
||
testLogger.startStep('步骤1: 描述步骤');
|
||
|
||
// 测试逻辑
|
||
|
||
testLogger.endStep('步骤1: 描述步骤', 'passed');
|
||
|
||
await screenshotHelper.takeScreenshotOnSuccess('test-name');
|
||
});
|
||
});
|
||
```
|
||
|
||
### 测试命名规范
|
||
|
||
- 测试套件:使用`test.describe()`组织相关测试
|
||
- 测试用例:使用`TC-模块-序号: 描述`格式
|
||
- 测试步骤:使用`步骤N: 描述`格式
|
||
|
||
### 测试最佳实践
|
||
|
||
1. **使用测试夹具**:充分利用框架提供的夹具,避免重复代码
|
||
2. **详细日志**:使用`testLogger`记录测试步骤,便于调试
|
||
3. **截图记录**:在关键步骤和测试结束时截图
|
||
4. **数据清理**:使用`testDataManager`管理测试数据,自动清理
|
||
5. **断言明确**:使用`assertionHelper`进行清晰的断言
|
||
6. **等待稳定**:使用`waitFor`等待元素状态稳定
|
||
|
||
## 运行测试
|
||
|
||
### 本地运行
|
||
|
||
```bash
|
||
# 运行所有测试
|
||
npm run test
|
||
|
||
# 运行特定测试文件
|
||
npx playwright test e2e/examples/user-management.spec.ts
|
||
|
||
# 运行特定测试用例
|
||
npx playwright test -g "TC-USER-001"
|
||
|
||
# 有头模式运行
|
||
npm run test:headed
|
||
|
||
# 调试模式
|
||
npm run test:debug
|
||
|
||
# UI模式
|
||
npm run test:ui
|
||
```
|
||
|
||
### Docker环境运行
|
||
|
||
```bash
|
||
# 启动测试环境
|
||
docker-compose -f docker-compose.test.yml up -d
|
||
|
||
# 等待服务启动
|
||
sleep 30
|
||
|
||
# 运行测试
|
||
npm run test
|
||
|
||
# 停止环境
|
||
docker-compose -f docker-compose.test.yml down
|
||
```
|
||
|
||
### 查看测试报告
|
||
|
||
```bash
|
||
# HTML报告
|
||
npm run test:report
|
||
|
||
# JSON报告
|
||
cat test-results/results.json
|
||
|
||
# JUnit报告
|
||
cat test-results/junit.xml
|
||
```
|
||
|
||
## CI/CD集成
|
||
|
||
### Woodpecker CI
|
||
|
||
测试框架已集成Woodpecker CI,配置文件位于项目根目录的`.woodpecker.yml`。
|
||
|
||
**触发条件**:
|
||
- 推送到main或develop分支
|
||
- 创建Pull Request
|
||
- 每天凌晨2点定时执行
|
||
|
||
**测试流程**:
|
||
1. 启动Docker测试环境
|
||
2. 并行运行E2E测试(4个分片)
|
||
3. 执行API集成测试
|
||
4. 生成HTML测试报告
|
||
5. 测试失败时发送Slack通知
|
||
|
||
**Pipeline结构**:
|
||
- `setup`: 初始化Docker环境
|
||
- `e2e-tests`: 执行端到端测试(并行4个分片)
|
||
- `api-tests`: 执行API集成测试
|
||
- `test-report`: 合并测试报告
|
||
- `notify-failure`: 测试失败时发送通知
|
||
- `nightly-tests`: 每日定时执行完整测试
|
||
|
||
详细配置说明请参考:[WOODPECKER_CI.md](../WOODPECKER_CI.md)
|
||
|
||
### 测试报告
|
||
|
||
测试完成后会生成以下报告:
|
||
|
||
1. **HTML报告**:交互式HTML报告,包含测试详情和截图
|
||
2. **JSON报告**:机器可读的JSON格式报告
|
||
3. **JUnit报告**:兼容JUnit的XML格式报告
|
||
|
||
报告位置:
|
||
- `playwright-report/`:HTML报告
|
||
- `test-results/results.json`:JSON报告
|
||
- `test-results/junit.xml`:JUnit报告
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 测试设计原则
|
||
|
||
- **测试金字塔**:70% API测试,20% 集成测试,10% E2E测试
|
||
- **独立性**:每个测试用例应该独立运行,不依赖其他测试
|
||
- **可重复性**:测试结果应该稳定可重复
|
||
- **快速反馈**:优先测试核心业务流程
|
||
|
||
### 2. 数据管理
|
||
|
||
- 使用`TestDataManager`创建和管理测试数据
|
||
- 测试完成后自动清理测试数据
|
||
- 避免硬编码测试数据,使用工厂模式生成
|
||
|
||
### 3. 错误处理
|
||
|
||
- 使用`try-catch`捕获预期异常
|
||
- 提供清晰的错误信息
|
||
- 失败时自动截图和记录日志
|
||
|
||
### 4. 性能优化
|
||
|
||
- 合理使用并行执行
|
||
- 避免不必要的等待
|
||
- 复用浏览器实例
|
||
|
||
### 5. 维护性
|
||
|
||
- 遵循代码规范
|
||
- 添加必要的注释
|
||
- 定期重构测试代码
|
||
- 更新测试文档
|
||
|
||
## 故障排查
|
||
|
||
### 常见问题
|
||
|
||
#### 1. 测试超时
|
||
|
||
**问题**:测试执行超时
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 增加超时时间
|
||
test.setTimeout(60000);
|
||
|
||
// 或在配置中设置
|
||
use: {
|
||
actionTimeout: 60000,
|
||
navigationTimeout: 60000
|
||
}
|
||
```
|
||
|
||
#### 2. 元素未找到
|
||
|
||
**问题**:无法定位页面元素
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 等待元素可见
|
||
await page.waitForSelector('.element', { timeout: 10000 });
|
||
|
||
// 使用更精确的选择器
|
||
await page.locator('.container .element').click();
|
||
```
|
||
|
||
#### 3. 测试数据冲突
|
||
|
||
**问题**:测试数据相互干扰
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 使用唯一标识符
|
||
const timestamp = Date.now();
|
||
const username = `test_user_${timestamp}`;
|
||
|
||
// 每个测试使用独立数据
|
||
beforeEach(async () => {
|
||
testUser = await testDataManager.createTestUser();
|
||
});
|
||
|
||
afterEach(async () => {
|
||
await testDataManager.cleanup();
|
||
});
|
||
```
|
||
|
||
#### 4. 环境配置问题
|
||
|
||
**问题**:无法连接到测试环境
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 检查环境变量
|
||
cat .env
|
||
|
||
# 验证服务状态
|
||
docker-compose ps
|
||
|
||
# 查看服务日志
|
||
docker-compose logs backend
|
||
```
|
||
|
||
### 调试技巧
|
||
|
||
#### 1. 使用调试模式
|
||
|
||
```bash
|
||
npm run test:debug
|
||
```
|
||
|
||
#### 2. 使用UI模式
|
||
|
||
```bash
|
||
npm run test:ui
|
||
```
|
||
|
||
#### 3. 查看详细日志
|
||
|
||
```typescript
|
||
testLogger.debug('调试信息');
|
||
testLogger.info('一般信息');
|
||
testLogger.warn('警告信息');
|
||
testLogger.error('错误信息', error);
|
||
```
|
||
|
||
#### 4. 截图和录屏
|
||
|
||
```typescript
|
||
// 失败时自动截图
|
||
await screenshotHelper.takeScreenshotOnFailure('test-name');
|
||
|
||
// 手动截图
|
||
await screenshotHelper.takeScreenshot('debug-point');
|
||
|
||
// 录屏(在playwright.config.ts中配置)
|
||
use: {
|
||
video: 'retain-on-failure'
|
||
}
|
||
```
|
||
|
||
### 性能优化
|
||
|
||
#### 1. 减少测试时间
|
||
|
||
```typescript
|
||
// 并行执行测试
|
||
workers: 4
|
||
|
||
// 跳过慢速测试
|
||
test.skip('慢速测试', async () => {});
|
||
|
||
// 使用项目分组
|
||
projects: [
|
||
{ name: 'fast', testMatch: '**/*.fast.spec.ts' },
|
||
{ name: 'slow', testMatch: '**/*.slow.spec.ts' }
|
||
]
|
||
```
|
||
|
||
#### 2. 优化等待时间
|
||
|
||
```typescript
|
||
// 使用智能等待
|
||
await page.waitForSelector('.element', { state: 'visible' });
|
||
|
||
// 避免固定等待
|
||
// 不推荐:await page.waitForTimeout(5000);
|
||
// 推荐:await page.waitForLoadState('networkidle');
|
||
```
|
||
|
||
## 贡献指南
|
||
|
||
### 添加新测试
|
||
|
||
1. 在`e2e/examples/`目录下创建新的测试文件
|
||
2. 遵循测试命名规范
|
||
3. 使用测试夹具和辅助工具
|
||
4. 添加详细的测试步骤和日志
|
||
5. 提交前运行测试确保通过
|
||
|
||
### 扩展框架
|
||
|
||
1. 在`e2e/helpers/`目录下添加新的辅助工具
|
||
2. 在`e2e/fixtures/test-fixtures.ts`中注册新的夹具
|
||
3. 更新文档说明新功能
|
||
4. 添加示例测试
|
||
|
||
## 许可证
|
||
|
||
MIT License
|
||
|
||
## 联系方式
|
||
|
||
如有问题或建议,请联系测试团队。
|