08ea5fbe98
添加用户管理视图、API和状态管理文件
E2E测试框架使用文档
目录
概述
本E2E测试框架基于Playwright构建,为uniapp和admin模块提供完整的端到端测试解决方案。框架采用模块化设计,支持前后端完全联通的测试场景,确保业务流程的完整性和正确性。
主要特性
- ✅ 基于Playwright的现代化E2E测试框架
- ✅ 支持uniapp和admin模块的全流程业务测试
- ✅ 完整的测试数据管理和清理机制
- ✅ 丰富的测试辅助工具(表单、表格、断言等)
- ✅ 详细的测试日志和截图功能
- ✅ 多种测试报告格式(HTML、JSON、JUnit)
- ✅ 完整的CI/CD集成支持
- ✅ 支持多浏览器和多设备测试
快速开始
环境要求
- Node.js >= 18.0.0
- npm >= 9.0.0
- Docker(用于运行测试环境)
安装依赖
cd everything-is-suitable-test
npm install
安装Playwright浏览器
npm run test:install
配置环境变量
复制环境变量示例文件:
cp .env.example .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
运行测试
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)
框架提供了一组自定义测试夹具,可以在测试中直接使用:
test('示例测试', async ({
page,
testConfig,
testLogger,
testDataManager,
apiHelper,
formHelper,
tableHelper,
screenshotHelper,
assertionHelper
}) => {
// 使用夹具进行测试
});
可用夹具
| 夹具名称 | 描述 |
|---|---|
testConfig |
测试配置管理 |
testLogger |
测试日志记录 |
testReporter |
测试报告生成 |
testDataManager |
测试数据管理 |
apiHelper |
API请求辅助 |
formHelper |
表单操作辅助 |
tableHelper |
表格操作辅助 |
screenshotHelper |
截图辅助 |
assertionHelper |
断言辅助 |
测试数据管理
TestDataManager提供完整的测试数据生命周期管理:
const testUser = await testDataManager.createTestUser({
realName: '测试用户',
email: 'test@example.com'
});
// 测试完成后自动清理
测试辅助工具
APIHelper
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
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
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
await assertionHelper.assertElementVisible(page, '.user-table');
await assertionHelper.assertElementText(page, '.user-name', '张三');
await assertionHelper.assertSuccessMessage(page);
await assertionHelper.assertAPISuccess(response);
ScreenshotHelper
await screenshotHelper.takeScreenshot('test-name');
await screenshotHelper.takeElementScreenshot('.element', 'element-name');
await screenshotHelper.takeScreenshotOnFailure('test-name');
await screenshotHelper.takeScreenshotOnSuccess('test-name');
编写测试
基本测试结构
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: 描述格式
测试最佳实践
- 使用测试夹具:充分利用框架提供的夹具,避免重复代码
- 详细日志:使用
testLogger记录测试步骤,便于调试 - 截图记录:在关键步骤和测试结束时截图
- 数据清理:使用
testDataManager管理测试数据,自动清理 - 断言明确:使用
assertionHelper进行清晰的断言 - 等待稳定:使用
waitFor等待元素状态稳定
运行测试
本地运行
# 运行所有测试
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环境运行
# 启动测试环境
docker-compose -f docker-compose.test.yml up -d
# 等待服务启动
sleep 30
# 运行测试
npm run test
# 停止环境
docker-compose -f docker-compose.test.yml down
查看测试报告
# 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点定时执行
测试流程:
- 启动Docker测试环境
- 并行运行E2E测试(4个分片)
- 执行API集成测试
- 生成HTML测试报告
- 测试失败时发送Slack通知
Pipeline结构:
setup: 初始化Docker环境e2e-tests: 执行端到端测试(并行4个分片)api-tests: 执行API集成测试test-report: 合并测试报告notify-failure: 测试失败时发送通知nightly-tests: 每日定时执行完整测试
详细配置说明请参考:WOODPECKER_CI.md
测试报告
测试完成后会生成以下报告:
- HTML报告:交互式HTML报告,包含测试详情和截图
- JSON报告:机器可读的JSON格式报告
- 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. 测试超时
问题:测试执行超时
解决方案:
// 增加超时时间
test.setTimeout(60000);
// 或在配置中设置
use: {
actionTimeout: 60000,
navigationTimeout: 60000
}
2. 元素未找到
问题:无法定位页面元素
解决方案:
// 等待元素可见
await page.waitForSelector('.element', { timeout: 10000 });
// 使用更精确的选择器
await page.locator('.container .element').click();
3. 测试数据冲突
问题:测试数据相互干扰
解决方案:
// 使用唯一标识符
const timestamp = Date.now();
const username = `test_user_${timestamp}`;
// 每个测试使用独立数据
beforeEach(async () => {
testUser = await testDataManager.createTestUser();
});
afterEach(async () => {
await testDataManager.cleanup();
});
4. 环境配置问题
问题:无法连接到测试环境
解决方案:
# 检查环境变量
cat .env
# 验证服务状态
docker-compose ps
# 查看服务日志
docker-compose logs backend
调试技巧
1. 使用调试模式
npm run test:debug
2. 使用UI模式
npm run test:ui
3. 查看详细日志
testLogger.debug('调试信息');
testLogger.info('一般信息');
testLogger.warn('警告信息');
testLogger.error('错误信息', error);
4. 截图和录屏
// 失败时自动截图
await screenshotHelper.takeScreenshotOnFailure('test-name');
// 手动截图
await screenshotHelper.takeScreenshot('debug-point');
// 录屏(在playwright.config.ts中配置)
use: {
video: 'retain-on-failure'
}
性能优化
1. 减少测试时间
// 并行执行测试
workers: 4
// 跳过慢速测试
test.skip('慢速测试', async () => {});
// 使用项目分组
projects: [
{ name: 'fast', testMatch: '**/*.fast.spec.ts' },
{ name: 'slow', testMatch: '**/*.slow.spec.ts' }
]
2. 优化等待时间
// 使用智能等待
await page.waitForSelector('.element', { state: 'visible' });
// 避免固定等待
// 不推荐:await page.waitForTimeout(5000);
// 推荐:await page.waitForLoadState('networkidle');
贡献指南
添加新测试
- 在
e2e/examples/目录下创建新的测试文件 - 遵循测试命名规范
- 使用测试夹具和辅助工具
- 添加详细的测试步骤和日志
- 提交前运行测试确保通过
扩展框架
- 在
e2e/helpers/目录下添加新的辅助工具 - 在
e2e/fixtures/test-fixtures.ts中注册新的夹具 - 更新文档说明新功能
- 添加示例测试
许可证
MIT License
联系方式
如有问题或建议,请联系测试团队。