高级QA工程师
自动化测试、覆盖率分析和质量保证模式,用于React和Next.js应用程序。
目录
快速开始
# 为React组件生成Jest测试存根
python scripts/test_suite_generator.py src/components/ --output __tests__/
# 从Jest/Istanbul报告分析测试覆盖率
python scripts/coverage_analyzer.py coverage/coverage-final.json --threshold 80
# 为Next.js路由搭建Playwright E2E测试
python scripts/e2e_test_scaffolder.py src/app/ --output e2e/
工具概览
1. 测试套件生成器
扫描React/TypeScript组件,并生成具有适当结构的Jest + React Testing Library测试存根。
输入: 包含React组件的源目录 输出: 带有describe块、渲染测试、交互测试的测试文件
用法:
# 基本用法 - 扫描组件并生成测试
python scripts/test_suite_generator.py src/components/ --output __tests__/
# 输出:
# 扫描:src/components/
# 发现24个React组件
#
# 生成的测试:
# __tests__/Button.test.tsx (渲染,点击处理程序,禁用状态)
# __tests__/Modal.test.tsx (渲染,打开/关闭,键盘事件)
# __tests__/Form.test.tsx (渲染,验证,提交)
# ...
#
# 摘要:24个测试文件,87个测试用例
# 包括可访问性测试
python scripts/test_suite_generator.py src/ --output __tests__/ --include-a11y
# 使用自定义模板生成
python scripts/test_suite_generator.py src/ --template custom-template.tsx
支持的模式:
- 带有钩子的函数组件
- 带有Context提供者的组件
- 带有数据获取的组件
- 带有验证的表单组件
2. 覆盖率分析器
解析Jest/Istanbul覆盖率报告,识别差距、未覆盖的分支,并提供可操作的建议。
输入: 覆盖率报告(JSON或LCOV格式) 输出: 带有建议的覆盖率分析
用法:
# 分析覆盖率报告
python scripts/coverage_analyzer.py coverage/coverage-final.json
# 输出:
# === 覆盖率分析报告 ===
# 总体:72.4%(目标:80%)
#
# 按类型:
# Statements: 74.2%
# Branches: 68.1%
# Functions: 71.8%
# Lines: 73.5%
#
# 临界差距(未覆盖的业务逻辑):
# src/services/payment.ts:45-67 - 支付处理
# src/hooks/useAuth.ts:23-41 - 认证流程
#
# 建议:
# 1. 为支付服务错误处理添加测试
# 2. 覆盖认证边缘情况
# 3. 测试表单验证分支
#
# 低于阈值(80%)的文件:
# src/components/Checkout.tsx: 45%
# src/services/api.ts: 62%
# 强制阈值(低于时退出1)
python scripts/coverage_analyzer.py coverage/ --threshold 80 --strict
# 生成HTML报告
python scripts/coverage_analyzer.py coverage/ --format html --output report.html
3. E2E测试脚手架
扫描Next.js页面/应用目录并生成带有常见交互的Playwright测试文件。
输入: Next.js页面或应用目录 输出: 按路由组织的Playwright测试文件
用法:
# 为Next.js App Router搭建E2E测试
python scripts/e2e_test_scaffolder.py src/app/ --output e2e/
# 输出:
# 扫描:src/app/
# 发现12条路由
#
# 生成的E2E测试:
# e2e/home.spec.ts (导航,英雄部分)
# e2e/auth/login.spec.ts (表单提交,验证)
# e2e/auth/register.spec.ts (注册流程)
# e2e/dashboard.spec.ts (认证路由)
# e2e/products/[id].spec.ts (动态路由)
# ...
#
# 生成:playwright.config.ts
# 生成:e2e/fixtures/auth.ts
# 包括页面对象模型类
python scripts/e2e_test_scaffolder.py src/app/ --output e2e/ --include-pom
# 为特定路由生成
python scripts/e2e_test_scaffolder.py src/app/ --routes "/login,/dashboard,/checkout"
QA工作流程
单元测试生成工作流程
用于为新组件或现有React组件设置测试。
步骤1:扫描项目中未测试的组件
python scripts/test_suite_generator.py src/components/ --scan-only
步骤2:生成测试存根
python scripts/test_suite_generator.py src/components/ --output __tests__/
步骤3:审查和自定义生成的测试
// __tests__/Button.test.tsx(生成)
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from '../src/components/Button';
describe('Button', () => {
it('渲染带有标签', () => {
render(<Button>Click me</Button>);
expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
});
it('点击时调用onClick', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click</Button>);
fireEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
// TODO: 添加您的特定测试用例
});
步骤4:运行测试并检查覆盖率
npm test -- --coverage
python scripts/coverage_analyzer.py coverage/coverage-final.json
覆盖率分析工作流程
用于提高测试覆盖率或准备发布。
步骤1:生成覆盖率报告
npm test -- --coverage --coverageReporters=json
步骤2:分析覆盖率差距
python scripts/coverage_analyzer.py coverage/coverage-final.json --threshold 80
步骤3:识别关键路径
python scripts/coverage_analyzer.py coverage/ --critical-paths
步骤4:生成缺失的测试存根
python scripts/test_suite_generator.py src/ --uncovered-only --output __tests__/
步骤5:验证改进
npm test -- --coverage
python scripts/coverage_analyzer.py coverage/ --compare previous-coverage.json
E2E测试设置工作流程
用于为Next.js项目设置Playwright。
步骤1:初始化Playwright(如果尚未安装)
npm init playwright@latest
步骤2:从路由搭建E2E测试
python scripts/e2e_test_scaffolder.py src/app/ --output e2e/
步骤3:配置认证固定装置
// e2e/fixtures/auth.ts(生成)
import { test as base } from '@playwright/test';
export const test = base.extend({
authenticatedPage: async ({ page }, use) => {
await page.goto('/login');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'password');
await page.click('button[type="submit"]');
await page.waitForURL('/dashboard');
await use(page);
},
});
步骤4:运行E2E测试
npx playwright test
npx playwright show-report
步骤5:添加到CI管道
# .github/workflows/e2e.yml
- name: 运行E2E测试
run: npx playwright test
- name: 上传报告
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
参考文档
| 文件 | 包含 | 使用时 |
|---|---|---|
references/testing_strategies.md |
测试金字塔,测试类型,覆盖率目标,CI/CD集成 | 设计测试策略 |
references/test_automation_patterns.md |
页面对象模型,模拟(MSW),固定装置,异步模式 | 编写测试代码 |
references/qa_best_practices.md |
可测试代码,易碎测试,调试,质量指标 | 提高测试质量 |
常见模式快速参考
React Testing Library查询
// 首选(可访问)
screen.getByRole('button', { name: /submit/i })
screen.getByLabelText(/email/i)
screen.getByPlaceholderText(/search/i)
// 回退
screen.getByTestId('custom-element')
异步测试
// 等待元素
await screen.findByText(/loaded/i);
// 等待移除
await waitForElementToBeRemoved(() => screen.queryByText(/loading/i));
// 等待条件
await waitFor(() => {
expect(mockFn).toHaveBeenCalled();
});
使用MSW模拟
import { rest } from 'msw';
import { setupServer } from 'msw/node';
const server = setupServer(
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.json([{ id: 1, name: 'John' }]));
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Playwright定位器
// 首选
page.getByRole('button', { name: 'Submit' })
page.getByLabel('Email')
page.getByText('Welcome')
// 链式
page.getByRole('listitem').filter({ hasText: 'Product' })
覆盖率阈值(jest.config.js)
module.exports = {
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};
常见命令
# Jest
npm test # 运行所有测试
npm test -- --watch # 监视模式
npm test -- --coverage # 带覆盖率
npm test -- Button.test.tsx # 单个文件
# Playwright
npx playwright test # 运行所有E2E测试
npx playwright test --ui # UI模式
npx playwright test --debug # 调试模式
npx playwright codegen # 生成测试
# 覆盖率
npm test -- --coverage --coverageReporters=lcov,json
python scripts/coverage_analyzer.py coverage/coverage-final.json