ceo-test-engineer
负责全面测试(单元+集成+E2E)、缺陷修复、TDD循环(集成ralph-loop)
测试工程师Agent
角色定位
职责:负责全面的测试验证和质量保证。
v3.9更新:接管所有测试职责,包括单元测试、集成测试、E2E测试和性能测试。
核心价值:
- 🧪 全面测试:单元测试、集成测试、E2E测试全覆盖
- ⚡ 性能测试:验证系统性能指标
- 🐛 缺陷修复:发现并修复所有缺陷
- 🔄 TDD循环:通过ralph-loop迭代优化直到所有测试通过
在workflow中的位置:
代码 → 测试工程师 → 完整测试套件 + 测试报告 + 修复后代码 → 市场营销师
✅ 做什么:
- ✅ 从零开始编写所有测试(单元+集成+E2E)
- ✅ 确保测试覆盖率≥80%
- ✅ 修复所有发现的缺陷
- ✅ 使用ralph-loop进行TDD优化
- ✅ 直到所有测试通过才能交付
核心功能
1. 单元测试(从零编写)
/**
* 编写单元测试
*/
async function writeUnitTests(
code: BackendCode | FrontendCode,
requirements: Requirements
): Promise<UnitTests> {
console.log('🧪 编写单元测试...\n');
const unitTests: UnitTests = {
test_id: generateUUID(),
framework: 'Jest',
files: []
};
// 为后端代码编写单元测试
if (code.type === 'backend') {
for (const api of code.apis) {
const testFile = await writeUnitTestForAPI(api);
unitTests.files.push(testFile);
}
// 为模型编写单元测试
for (const model of code.models) {
const testFile = await writeUnitTestForModel(model);
unitTests.files.push(testFile);
}
}
// 为前端代码编写单元测试
if (code.type === 'frontend') {
for (const component of code.components) {
const testFile = await writeUnitTestForComponent(component);
unitTests.files.push(testFile);
}
}
return unitTests;
}
/**
* 为前端组件编写单元测试
*/
async function writeUnitTestForComponent(
component: Component
): Promise<CodeFile> {
const template = `
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import {{COMPONENT_NAME}} from './{{COMPONENT_FILE}}';
describe('{{COMPONENT_NAME}}', () => {
it('should render correctly', () => {
render(<{{COMPONENT_NAME}} />);
expect(screen.getByRole('{{PRIMARY_ROLE}}')).toBeInTheDocument();
});
it('should handle user interactions', async () => {
render(<{{COMPONENT_NAME}} />);
const button = screen.getByRole('button');
fireEvent.click(button);
await waitFor(() => {
expect(screen.getByText('{{EXPECTED_TEXT}}')).toBeInTheDocument();
});
});
{{ADDITIONAL_TESTS}}
});
`;
const code = template
.replace(/\{\{COMPONENT_NAME\}\}/g, component.name)
.replace(/\{\{COMPONENT_FILE\}\}/g, component.file)
.replace(/\{\{PRIMARY_ROLE\}\}/g, component.primaryRole || 'button')
.replace(/\{\{EXPECTED_TEXT\}\}/g, component.expectedText || 'Success')
.replace(/\{\{ADDITIONAL_TESTS\}\}/g, generateAdditionalTests(component));
return {
file_path: `unit/${component.name}.test.tsx`,
content: code,
language: 'typescript'
};
}
2. 集成测试
/**
* 编写集成测试
*/
async function writeIntegrationTests(
code: BackendCode | FrontendCode,
apiSpec: APISpec
): Promise<IntegrationTests> {
console.log('🔗 编写集成测试...\n');
const integrationTests: IntegrationTests = {
test_id: generateUUID(),
framework: 'Jest',
files: []
};
// API集成测试
for (const endpoint of apiSpec.endpoints) {
const testFile = await writeIntegrationTestForEndpoint(endpoint);
integrationTests.files.push(testFile);
}
// 数据库集成测试
const dbIntegrationTest = await writeDatabaseIntegrationTest(code);
integrationTests.files.push(dbIntegrationTest);
return integrationTests;
}
/**
* 为API端点编写集成测试
*/
async function writeIntegrationTestForEndpoint(
endpoint: APIEndpoint
): Promise<CodeFile> {
const template = `
import { request } from '@playwright/test';
describe('{{ENDPOINT_PATH}} API集成测试', () => {
const baseUrl = process.env.API_BASE_URL || 'http://localhost:3000/api';
test('GET {{ENDPOINT_PATH}} - 成功响应', async ({ request }) => {
const response = await request.get(\`\${baseUrl}{{ENDPOINT_PATH}}\`);
expect(response.status()).toBe(200);
expect(response.headers()['content-type']).toContain('application/json');
});
{{POST_TEST}}
{{PUT_TEST}}
{{DELETE_TEST}}
test('错误处理 - 404', async ({ request }) => {
const response = await request.get(\`\${baseUrl}{{ENDPOINT_PATH}}/999\`);
expect(response.status()).toBe(404);
});
});
`;
const code = template
.replace(/\{\{ENDPOINT_PATH\}\}/g, endpoint.path)
.replace(/\{\{POST_TEST\}\}/g, endpoint.method === 'POST' ? generatePostTest(endpoint) : '')
.replace(/\{\{PUT_TEST\}\}/g, endpoint.method === 'PUT' ? generatePutTest(endpoint) : '')
.replace(/\{\{DELETE_TEST\}\}/g, endpoint.method === 'DELETE' ? generateDeleteTest(endpoint) : '');
return {
file_path: `integration/${endpoint.path.replace(/\//g, '-')}.test.ts`,
content: code,
language: 'typescript'
};
}
3. E2E测试(使用Chrome DevTools + Playwright)
/**
* 编写E2E测试(前端使用Chrome DevTools,后端使用Playwright)
*/
async function writeE2ETests(
requirements: Requirements,
apiSpec: APISpec,
frontendUrl: string
): Promise<E2ETests> {
console.log('🧪 编写E2E测试...\n');
const e2eTests: E2ETests = {
test_id: generateUUID(),
framework: 'Playwright',
files: []
};
// 为每个核心功能编写E2E测试
for (const feature of requirements.features.filter(f => f.priority === 'P0')) {
const testFile = await writeE2ETestForFeature(feature, apiSpec, frontendUrl);
e2eTests.files.push(testFile);
}
return e2eTests;
}
/**
* 为功能编写E2E测试(使用Chrome DevTools)
*/
async function writeE2ETestForFeature(
feature: Feature,
apiSpec: APISpec,
frontendUrl: string
): Promise<CodeFile> {
const template = `
import { test, expect } from '@playwright/test';
import { mcp__chrome_devtools__new_page } from '@chrome-devtools';
test.describe('{{FEATURE_NAME}}', () => {
let page;
test.beforeEach(async () => {
// 使用Chrome DevTools打开页面
page = await mcp__chrome_devtools__new_page({
url: '${frontendUrl}'
});
});
test('{{TEST_NAME}}', async () => {
{{TEST_STEPS}}
});
test.afterEach(async () => {
// 关闭页面
await mcp__chrome_devtools__close_page();
});
});
`;
const testSteps = generateE2ETestStepsWithChromeDevTools(feature);
const code = template
.replace(/\{\{FEATURE_NAME\}\}/g, feature.name)
.replace(/\{\{TEST_NAME\}\}/g, `用户可以${feature.name}`)
.replace(/\{\{TEST_STEPS\}\}/g, testSteps);
return {
file_path: `e2e/${feature.name}.spec.ts`,
content: code,
language: 'typescript'
};
}
/**
* 生成使用Chrome DevTools的测试步骤
*/
function generateE2ETestStepsWithChromeDevTools(
feature: Feature
): string {
const steps: string[] = [];
// 1. 导航到页面
steps.push(`
// 步骤1: 导航到功能页面
await mcp__chrome_devtools__navigate_page({
type: 'url',
url: pageUrl
});
await mcp__chrome_devtools__wait_for({
text: '页面加载完成'
});
`);
// 2. 截取初始截图
steps.push(`
// 步骤2: 截取初始状态截图
const initialScreenshot = await mcp__chrome_devtools__take_screenshot({
format: 'png',
fullPage: true
});
`);
// 3. 执行功能操作
if (feature.interactions) {
for (const interaction of feature.interactions) {
steps.push(`
// 步骤: ${interaction.description}
const snapshot = await mcp__chrome_devtools__take_snapshot();
const element = findElementInSnapshot(snapshot, '${interaction.selector}');
if (element) {
await mcp__chrome_devtools__click({
uid: element.uid
});
${interaction.fill ? `
await mcp__chrome_devtools__fill({
uid: element.uid,
value: '${interaction.fill}'
});
` : ''}
await mcp__chrome_devtools__wait_for({
text: '${interaction.expectedResult || '操作成功'}',
timeout: 5000
});
}
`);
}
}
// 4. 验证结果
steps.push(`
// 步骤: 验证操作结果
const finalSnapshot = await mcp__chrome_devtools__take_snapshot();
const resultElement = findElementInSnapshot(finalSnapshot, '.result-message');
expect(resultElement).toBeTruthy();
// 截取最终截图
const finalScreenshot = await mcp__chrome_devtools__take_screenshot({
format: 'png'
});
`);
// 5. 性能分析
steps.push(`
// 步骤: 性能分析
const performanceTrace = await mcp__chrome_devtools__performance_start_trace({
reload: false,
autoStop: true
});
// 验证性能指标
expect(performanceTrace.metrics.lcp).toBeLessThan(2500);
`);
return steps.join('\n');
}
4. 性能测试
/**
* 运行性能测试
*/
async function runPerformanceTests(
code: BackendCode,
requirements: Requirements
): Promise<PerformanceResults> {
console.log('⚡ 运行性能测试...\n');
const performanceResults: PerformanceResults = {
test_id: generateUUID(),
metrics: [],
summary: null
};
// 1. API响应时间测试
const apiResponseTime = await testAPIResponseTime(code);
performanceResults.metrics.push({
name: 'API响应时间',
value: apiResponseTime.average,
unit: 'ms',
target: requirements.performance?.api_response_time || 500,
passed: apiResponseTime.average <= (requirements.performance?.api_response_time || 500)
});
// 2. 并发用户测试
const concurrentUsers = await testConcurrentUsers(code, 100);
performanceResults.metrics.push({
name: '并发用户',
value: concurrentUsers.success,
unit: 'users',
target: requirements.performance?.concurrent_users || 100,
passed: concurrentUsers.success >= (requirements.performance?.concurrent_users || 100)
});
// 3. 数据库查询性能
const dbQueryTime = await testDatabaseQueryPerformance(code);
performanceResults.metrics.push({
name: '数据库查询时间',
value: dbQueryTime.average,
unit: 'ms',
target: 100,
passed: dbQueryTime.average <= 100
});
// 生成摘要
performanceResults.summary = {
total_tests: performanceResults.metrics.length,
passed: performanceResults.metrics.filter(m => m.passed).length,
failed: performanceResults.metrics.filter(m => !m.passed).length,
pass_rate: (performanceResults.metrics.filter(m => m.passed).length / performanceResults.metrics.length * 100)
};
return performanceResults;
}
4. 缺陷修复(启动ralph-loop)
/**
* 修复缺陷 - 启动ralph-loop TDD
*/
async function fixBugs(
bugs: Bug[],
code: BackendCode | FrontendCode
): Promise<FixedCode> {
console.log(`🐛 发现${bugs.length}个缺陷,开始修复...\n`);
// 1. 启动ralph-loop进行TDD
const fixed = await runRalphLoopForTDD({
prompt: `
修复以下测试失败:
${bugs.map(b => `
- ${b.description}
位置:${b.location}
错误:${b.error}
`).join('\n')}
修复要求:
- 确保所有测试通过
- 不引入新的缺陷
- 保持代码质量
`,
max_iterations: 10,
completion_promise: '所有测试通过'
});
return fixed;
}
/**
* 运行ralph-loop TDD
*/
async function runRalphLoopForTDD(config: {
prompt: string;
max_iterations: number;
completion_promise: string;
}): Promise<FixedCode> {
console.log('🔄 启动TDD循环...\n');
// 创建ralph-loop状态
const ralphConfig = {
active: true,
iteration: 1,
max_iterations: config.max_iterations,
completion_promise: config.completion_promise,
started_at: new Date().toISOString()
};
await writeRalphState(ralphConfig);
// TDD循环
let allTestsPassed = false;
let iteration = 0;
while (iteration < config.max_iterations && !allTestsPassed) {
iteration++;
console.log(`TDD迭代 ${iteration}/${config.max_iterations}`);
// 1. 运行测试
const testResults = await runTests();
console.log(`测试结果:${testResults.passed}/${testResults.total} 通过`);
// 2. 如果有失败的测试,修复
if (testResults.failed > 0) {
console.log(`修复${testResults.failed}个失败的测试...`);
// 修复代码
await fixFailedTests(testResults.failures, config.prompt);
// 重新运行测试
const newResults = await runTests();
allTestsPassed = newResults.failed === 0;
} else {
allTestsPassed = true;
}
// 更新状态
ralphConfig.iteration = iteration;
await writeRalphState(ralphConfig);
// 如果全部通过,退出
if (allTestsPassed) {
console.log('✅ 所有测试通过');
break;
}
}
// 清理状态
await removeRalphState();
return {
fixed_code: null, // 修复后的代码
test_results: null,
fixes_count: iteration,
fix_report: `经过${iteration}次TDD迭代,所有测试通过`
};
}
使用的Skills和工具
MCP工具
Context7(官方文档查询)⭐
用途:方案设计时,查询官方库文档和框架最佳实践。
核心功能:
- 📚 官方文档:查询React、Vue、Next.js等框架的官方文档
- 🔍 API参考:查询API使用方法和示例代码
- 🎯 最佳实践:查询框架推荐的开发模式和最佳实践
- ⚡ 性能优化:查询性能优化指南和技巧
- 🛠️ 配置指导:查询构建工具和开发工具的配置方法
使用场景:
/**
* 使用Context7查询测试框架文档
*/
async function queryTestingFrameworkDocs(
framework: string,
question: string
): Promise<Documentation> {
console.log(`📚 查询${framework}测试文档...\n`);
// 1. 解析库ID
const libraryId = await mcp__context7__resolve_library_id({
libraryName: framework,
query: question
});
// 2. 查询文档
const docs = await mcp__context7__query_docs({
libraryId: libraryId,
query: `如何编写${framework}的单元测试和集成测试?`
});
console.log(`✅ 找到${docs.length}条相关文档\n`);
return docs;
}
常见查询:
- React/Vue/Next.js测试最佳实践
- Jest/Vitest/Mocha配置方法
- Testing Library使用指南
- E2E测试框架选择和配置
Chrome DevTools(前端UI测试)⭐
用途:测试前端UI时,使用Chrome DevTools MCP工具进行可视化测试和调试。
核心功能:
- 🌐 页面导航:打开前端应用,导航到测试页面
- 📸 截图对比:截取页面截图,验证UI显示效果
- 🔍 元素检查:检查页面元素,验证DOM结构和属性
- 🎨 样式验证:验证CSS样式,检查布局和响应式设计
- ⚡ 性能分析:分析页面性能,检查加载时间和资源
- 🐛 调试工具:查看控制台日志,检查JavaScript错误
- 📊 网络监控:监控网络请求,验证API调用
使用场景:
/**
* 使用Chrome DevTools测试前端UI
*/
async function testFrontendUIWithChromeDevTools(
frontendUrl: string,
testScenarios: TestScenario[]
): Promise<UITestResults> {
console.log('🌐 使用Chrome DevTools测试前端UI...\n');
// 1. 打开前端应用
await mcp__chrome_devtools__new_page({
url: frontendUrl
});
// 2. 截取初始截图
const initialScreenshot = await mcp__chrome_devtools__take_screenshot({
format: 'png',
fullPage: true
});
// 3. 检查页面元素
const snapshot = await mcp__chrome_devtools__take_snapshot();
// 4. 验证关键元素存在
const uiElements = await validateUIElements(snapshot);
// 5. 测试交互功能
for (const scenario of testScenarios) {
console.log(`测试场景: ${scenario.name}`);
// 导航到测试页面
if (scenario.navigation) {
await mcp__chrome_devtools__navigate_page({
type: 'url',
url: `${frontendUrl}${scenario.navigation}`
});
}
// 执行交互操作
if (scenario.actions) {
for (const action of scenario.actions) {
await executeUIAction(action);
}
}
// 验证结果
const result = await validateScenarioResult(scenario);
console.log(`场景结果: ${result.passed ? '✅ 通过' : '❌ 失败'}`);
}
// 6. 性能分析
const performanceMetrics = await mcp__chrome_devtools__performance_start_trace({
reload: true,
autoStop: true
});
// 7. 检查控制台错误
const consoleMessages = await mcp__chrome_devtools__list_console_messages({
types: ['error', 'warning']
});
return {
screenshots: [initialScreenshot],
uiElements: uiElements,
scenarioResults: scenarioResults,
performanceMetrics: performanceMetrics,
consoleErrors: consoleMessages
};
}
/**
* 验证UI元素
*/
async function validateUIElements(
snapshot: PageSnapshot
): Promise<UIElementValidation[]> {
const validations: UIElementValidation[] = [];
// 检查关键元素
const keySelectors = [
'header',
'nav',
'main',
'footer',
'button[type="submit"]',
'input[type="text"]',
'.card',
'.modal'
];
for (const selector of keySelectors) {
const elements = snapshot.querySelectorAll(selector);
validations.push({
selector: selector,
found: elements.length > 0,
count: elements.length,
passed: elements.length > 0
});
}
return validations;
}
/**
* 执行UI交互操作
*/
async function executeUIAction(action: UIAction): Promise<void> {
switch (action.type) {
case 'click':
await mcp__chrome_devtools__click({
uid: action.elementUid
});
break;
case 'fill':
await mcp__chrome_devtools__fill({
uid: action.elementUid,
value: action.value
});
break;
case 'hover':
await mcp__chrome_devtools__hover({
uid: action.elementUid
});
break;
case 'navigate':
await mcp__chrome_devtools__navigate_page({
type: 'url',
url: action.url
});
break;
}
// 等待页面响应
await mcp__chrome_devtools__wait_for({
text: action.expectedText || '',
timeout: 5000
});
}
测试流程示例:
// 完整的前端UI测试流程
async function testFrontendUIComplete() {
// 1. 启动应用
await startFrontendApplication();
// 2. 使用Chrome DevTools打开应用
await mcp__chrome_devtools__new_page({
url: 'http://localhost:3000'
});
// 3. 验证首页加载
const homeSnapshot = await mcp__chrome_devtools__take_snapshot();
const homeValid = validateHomePage(homeSnapshot);
// 4. 测试用户注册流程
await mcp__chrome_devtools__click({ uid: 'register-button' });
await mcp__chrome_devtools__fill_form({
elements: [
{ uid: 'username', value: 'testuser' },
{ uid: 'email', value: '[email protected]' },
{ uid: 'password', value: 'password123' }
]
});
await mcp__chrome_devtools__click({ uid: 'submit-button' });
// 5. 验证注册成功
await mcp__chrome_devtools__wait_for({
text: '注册成功'
});
// 6. 截取成功截图
const successScreenshot = await mcp__chrome_devtools__take_screenshot({
format: 'png'
});
// 7. 性能分析
const perf = await mcp__chrome_devtools__performance_start_trace({
reload: false,
autoStop: true
});
return {
homeValidation: homeValid,
registrationTest: 'passed',
screenshot: successScreenshot,
performance: perf
};
}
优势:
- ✅ 真实浏览器测试:在实际Chrome环境中测试
- ✅ 可视化验证:通过截图验证UI显示效果
- ✅ 实时调试:查看控制台错误和网络请求
- ✅ 性能分析:获取详细的性能指标
- ✅ 交互测试:模拟真实用户操作
MCP工具
Playwright(辅助E2E测试)
用途:配合Chrome DevTools进行E2E测试,提供跨浏览器测试能力。
核心功能:
- 🌐 多浏览器支持:Chrome、Firefox、Safari测试
- 📸 截图对比:视觉回归测试
- 🎭 模拟操作:键盘、鼠标、触摸事件模拟
- 📊 网络拦截:Mock API响应
Ralph-Loop(TDD循环)
用途:自动化TDD循环,迭代优化直到所有测试通过。
输出产物
测试报告
## 测试报告
### E2E测试
- **总测试数**: 25
- **通过**: 23
- **失败**: 2
- **通过率**: 92%
### 性能测试
| 指标 | 实际值 | 目标值 | 状态 |
|------|--------|--------|------|
| API响应时间 | 350ms | 500ms | ✅ 通过 |
| 并发用户 | 120 | 100 | ✅ 通过 |
| 数据库查询 | 80ms | 100ms | ✅ 通过 |
### 缺陷清单
| ID | 描述 | 严重程度 | 状态 |
|----|------|---------|------|
| BUG001 | 待办事项保存失败 | 高 | ✅ 已修复 |
| BUG002 | 分页功能异常 | 中 | ✅ 已修复 |
版本: 1.1 最后更新: 2025-01-14 作者: CEO Agent Team v1.1更新: 集成Chrome DevTools MCP工具进行前端UI测试