测试 API
本文档描述了 Trae 测试功能的 API 接口。
概述
测试 API 提供了单元测试、集成测试、端到端测试的运行、管理和报告功能,帮助开发者确保代码质量。
端点
运行测试
http
POST /api/testing/run请求参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
project_id | string | 是 | 项目 ID |
test_type | string | 否 | 测试类型 (unit/integration/e2e/all) |
test_files | array | 否 | 指定测试文件 |
test_pattern | string | 否 | 测试文件匹配模式 |
environment | string | 否 | 测试环境 (development/staging/production) |
parallel | boolean | 否 | 是否并行运行 |
coverage | boolean | 否 | 是否生成覆盖率报告 |
watch | boolean | 否 | 是否监听文件变化 |
请求示例
json
{
"project_id": "proj_123",
"test_type": "unit",
"test_pattern": "**/*.test.js",
"environment": "development",
"parallel": true,
"coverage": true,
"watch": false
}响应
json
{
"test_run_id": "run_456",
"status": "running",
"started_at": "2024-01-01T12:00:00Z",
"estimated_duration": 120,
"test_count": {
"total": 156,
"unit": 120,
"integration": 30,
"e2e": 6
},
"progress": {
"completed": 0,
"running": 5,
"pending": 151
}
}获取测试运行状态
http
GET /api/testing/runs/{test_run_id}响应
json
{
"test_run_id": "run_456",
"project_id": "proj_123",
"status": "completed",
"started_at": "2024-01-01T12:00:00Z",
"completed_at": "2024-01-01T12:02:30Z",
"duration": 150,
"summary": {
"total": 156,
"passed": 148,
"failed": 6,
"skipped": 2,
"success_rate": 94.87
},
"coverage": {
"lines": 85.6,
"functions": 92.3,
"branches": 78.9,
"statements": 86.2
},
"performance": {
"average_duration": 0.96,
"slowest_test": {
"name": "integration test for user authentication",
"duration": 5.2,
"file": "tests/auth.integration.test.js"
},
"fastest_test": {
"name": "utility function validation",
"duration": 0.02,
"file": "tests/utils.test.js"
}
}
}获取测试结果详情
http
GET /api/testing/runs/{test_run_id}/results?status={status}&limit={limit}&offset={offset}查询参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
status | string | 否 | 过滤状态 (passed/failed/skipped) |
limit | number | 否 | 返回数量限制 |
offset | number | 否 | 偏移量 |
file | string | 否 | 过滤文件 |
suite | string | 否 | 过滤测试套件 |
响应
json
{
"test_run_id": "run_456",
"total": 156,
"results": [
{
"test_id": "test_789",
"name": "should authenticate user with valid credentials",
"suite": "Authentication",
"file": "tests/auth.test.js",
"status": "passed",
"duration": 1.2,
"started_at": "2024-01-01T12:00:05Z",
"completed_at": "2024-01-01T12:00:06Z",
"assertions": {
"total": 5,
"passed": 5,
"failed": 0
}
},
{
"test_id": "test_790",
"name": "should reject invalid password",
"suite": "Authentication",
"file": "tests/auth.test.js",
"status": "failed",
"duration": 0.8,
"started_at": "2024-01-01T12:00:07Z",
"completed_at": "2024-01-01T12:00:08Z",
"error": {
"message": "Expected status code 401 but received 500",
"stack": "AssertionError: Expected status code 401 but received 500\n at test (/tests/auth.test.js:45:12)",
"type": "AssertionError"
},
"assertions": {
"total": 3,
"passed": 2,
"failed": 1
}
}
]
}停止测试运行
http
POST /api/testing/runs/{test_run_id}/stop响应
json
{
"test_run_id": "run_456",
"status": "stopped",
"stopped_at": "2024-01-01T12:01:30Z",
"reason": "user_requested",
"partial_results": {
"completed": 45,
"running": 3,
"pending": 108
}
}获取测试覆盖率报告
http
GET /api/testing/runs/{test_run_id}/coverage响应
json
{
"test_run_id": "run_456",
"overall": {
"lines": 85.6,
"functions": 92.3,
"branches": 78.9,
"statements": 86.2
},
"files": [
{
"file_path": "src/auth/authentication.js",
"lines": {
"total": 120,
"covered": 108,
"percentage": 90.0
},
"functions": {
"total": 15,
"covered": 14,
"percentage": 93.3
},
"branches": {
"total": 24,
"covered": 20,
"percentage": 83.3
},
"uncovered_lines": [45, 67, 89, 102, 115, 118],
"uncovered_functions": ["handleEdgeCase"],
"uncovered_branches": [
{
"line": 45,
"branch": "else",
"condition": "user.isActive === false"
}
]
}
],
"directories": [
{
"path": "src/auth/",
"lines": 88.5,
"functions": 91.2,
"branches": 82.1,
"statements": 89.3
},
{
"path": "src/utils/",
"lines": 95.2,
"functions": 98.1,
"branches": 89.7,
"statements": 96.0
}
]
}获取测试历史
http
GET /api/testing/history?project_id={project_id}&limit={limit}&offset={offset}查询参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
project_id | string | 是 | 项目 ID |
limit | number | 否 | 返回数量限制 |
offset | number | 否 | 偏移量 |
date_from | string | 否 | 开始日期 |
date_to | string | 否 | 结束日期 |
status | string | 否 | 过滤状态 |
响应
json
{
"project_id": "proj_123",
"total": 45,
"runs": [
{
"test_run_id": "run_456",
"started_at": "2024-01-01T12:00:00Z",
"completed_at": "2024-01-01T12:02:30Z",
"duration": 150,
"status": "completed",
"trigger": "manual",
"triggered_by": "user_123",
"summary": {
"total": 156,
"passed": 148,
"failed": 6,
"skipped": 2,
"success_rate": 94.87
},
"coverage": {
"lines": 85.6,
"change": "+2.3"
}
}
],
"trends": {
"success_rate": {
"current": 94.87,
"previous": 92.56,
"trend": "improving"
},
"coverage": {
"current": 85.6,
"previous": 83.3,
"trend": "improving"
},
"duration": {
"current": 150,
"previous": 165,
"trend": "improving"
}
}
}配置测试设置
http
PUT /api/testing/projects/{project_id}/settings请求参数
json
{
"frameworks": {
"unit": "jest",
"integration": "jest",
"e2e": "playwright"
},
"patterns": {
"unit": ["**/*.test.js", "**/*.spec.js"],
"integration": ["**/*.integration.test.js"],
"e2e": ["**/*.e2e.test.js"]
},
"coverage": {
"enabled": true,
"threshold": {
"lines": 80,
"functions": 85,
"branches": 75,
"statements": 80
},
"exclude": ["node_modules/**", "dist/**", "**/*.config.js"]
},
"parallel": {
"enabled": true,
"max_workers": 4
},
"timeout": {
"unit": 5000,
"integration": 30000,
"e2e": 60000
},
"environment": {
"NODE_ENV": "test",
"API_URL": "http://localhost:3001",
"DATABASE_URL": "sqlite://memory"
},
"notifications": {
"on_failure": true,
"on_success": false,
"on_coverage_drop": true,
"channels": ["email", "slack"]
}
}响应
json
{
"project_id": "proj_123",
"settings": {
"frameworks": {
"unit": "jest",
"integration": "jest",
"e2e": "playwright"
},
"patterns": {
"unit": ["**/*.test.js", "**/*.spec.js"],
"integration": ["**/*.integration.test.js"],
"e2e": ["**/*.e2e.test.js"]
},
"coverage": {
"enabled": true,
"threshold": {
"lines": 80,
"functions": 85,
"branches": 75,
"statements": 80
}
}
},
"updated_at": "2024-01-01T12:00:00Z"
}获取测试统计
http
GET /api/testing/projects/{project_id}/statistics?period={period}查询参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
period | string | 否 | 统计周期 (day/week/month/quarter/year) |
响应
json
{
"project_id": "proj_123",
"period": "month",
"summary": {
"total_runs": 45,
"total_tests": 7020,
"average_success_rate": 93.2,
"average_coverage": 84.1,
"average_duration": 142
},
"trends": {
"success_rate": [
{ "date": "2024-01-01", "value": 91.5 },
{ "date": "2024-01-02", "value": 92.1 },
{ "date": "2024-01-03", "value": 93.8 }
],
"coverage": [
{ "date": "2024-01-01", "value": 82.3 },
{ "date": "2024-01-02", "value": 83.1 },
{ "date": "2024-01-03", "value": 85.6 }
],
"duration": [
{ "date": "2024-01-01", "value": 165 },
{ "date": "2024-01-02", "value": 158 },
{ "date": "2024-01-03", "value": 150 }
]
},
"test_types": {
"unit": {
"count": 5400,
"success_rate": 95.2,
"average_duration": 0.8
},
"integration": {
"count": 1350,
"success_rate": 89.6,
"average_duration": 3.2
},
"e2e": {
"count": 270,
"success_rate": 85.1,
"average_duration": 12.5
}
},
"flaky_tests": [
{
"name": "user login flow",
"file": "tests/auth.e2e.test.js",
"failure_rate": 15.2,
"last_failure": "2024-01-03T10:30:00Z"
}
]
}WebSocket 实时更新
javascript
// 连接 WebSocket 获取实时测试更新
const ws = new WebSocket('wss://api.trae.ai/testing/ws');
ws.onopen = () => {
// 订阅测试运行更新
ws.send(JSON.stringify({
type: 'subscribe',
channel: 'test_run',
test_run_id: 'run_456'
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'test_started':
console.log(`测试开始: ${data.test_name}`);
break;
case 'test_completed':
console.log(`测试完成: ${data.test_name} - ${data.status}`);
if (data.status === 'failed') {
console.error(`错误: ${data.error.message}`);
}
break;
case 'run_progress':
console.log(`进度: ${data.completed}/${data.total} (${data.percentage}%)`);
break;
case 'run_completed':
console.log(`测试运行完成: ${data.summary.passed}/${data.summary.total} 通过`);
break;
}
};示例
运行单元测试
javascript
// 运行项目的所有单元测试
const runTests = async (projectId) => {
const response = await fetch('/api/testing/run', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
body: JSON.stringify({
project_id: projectId,
test_type: 'unit',
parallel: true,
coverage: true
})
});
const testRun = await response.json();
console.log(`测试运行已启动: ${testRun.test_run_id}`);
// 轮询测试状态
const checkStatus = async () => {
const statusResponse = await fetch(`/api/testing/runs/${testRun.test_run_id}`);
const status = await statusResponse.json();
console.log(`状态: ${status.status}, 进度: ${status.progress?.completed || 0}/${status.test_count?.total || 0}`);
if (status.status === 'completed') {
console.log('测试完成!');
console.log(`成功率: ${status.summary.success_rate}%`);
console.log(`覆盖率: ${status.coverage.lines}%`);
return status;
} else if (status.status === 'failed') {
console.error('测试运行失败');
return status;
}
// 继续轮询
setTimeout(checkStatus, 2000);
};
return checkStatus();
};
// 使用示例
runTests('proj_123');获取失败测试详情
javascript
// 获取失败的测试详情
const getFailedTests = async (testRunId) => {
const response = await fetch(`/api/testing/runs/${testRunId}/results?status=failed`);
const results = await response.json();
console.log(`找到 ${results.results.length} 个失败的测试:`);
results.results.forEach(test => {
console.log(`\n❌ ${test.name}`);
console.log(` 文件: ${test.file}`);
console.log(` 套件: ${test.suite}`);
console.log(` 错误: ${test.error.message}`);
if (test.error.stack) {
console.log(` 堆栈:\n${test.error.stack}`);
}
});
};
// 使用示例
getFailedTests('run_456');生成测试报告
javascript
// 生成详细的测试报告
const generateTestReport = async (testRunId) => {
// 获取测试运行详情
const runResponse = await fetch(`/api/testing/runs/${testRunId}`);
const run = await runResponse.json();
// 获取覆盖率报告
const coverageResponse = await fetch(`/api/testing/runs/${testRunId}/coverage`);
const coverage = await coverageResponse.json();
// 获取所有测试结果
const resultsResponse = await fetch(`/api/testing/runs/${testRunId}/results?limit=1000`);
const results = await resultsResponse.json();
// 生成报告
const report = {
summary: {
run_id: testRunId,
duration: run.duration,
started_at: run.started_at,
completed_at: run.completed_at,
total_tests: run.summary.total,
passed: run.summary.passed,
failed: run.summary.failed,
skipped: run.summary.skipped,
success_rate: run.summary.success_rate
},
coverage: {
overall: coverage.overall,
by_directory: coverage.directories
},
failed_tests: results.results.filter(test => test.status === 'failed'),
slow_tests: results.results
.filter(test => test.duration > 2)
.sort((a, b) => b.duration - a.duration)
.slice(0, 10),
performance: {
average_duration: run.performance.average_duration,
slowest_test: run.performance.slowest_test,
fastest_test: run.performance.fastest_test
}
};
console.log('📊 测试报告');
console.log('='.repeat(50));
console.log(`运行时间: ${report.summary.duration}s`);
console.log(`总测试数: ${report.summary.total_tests}`);
console.log(`✅ 通过: ${report.summary.passed}`);
console.log(`❌ 失败: ${report.summary.failed}`);
console.log(`⏭️ 跳过: ${report.summary.skipped}`);
console.log(`📈 成功率: ${report.summary.success_rate}%`);
console.log(`📊 代码覆盖率: ${report.coverage.overall.lines}%`);
if (report.failed_tests.length > 0) {
console.log('\n❌ 失败的测试:');
report.failed_tests.forEach(test => {
console.log(` - ${test.name} (${test.file})`);
});
}
if (report.slow_tests.length > 0) {
console.log('\n🐌 最慢的测试:');
report.slow_tests.forEach(test => {
console.log(` - ${test.name}: ${test.duration}s`);
});
}
return report;
};
// 使用示例
generateTestReport('run_456');配置持续集成
javascript
// 配置 CI/CD 测试流水线
const setupCITesting = async (projectId) => {
const settings = {
frameworks: {
unit: 'jest',
integration: 'jest',
e2e: 'playwright'
},
patterns: {
unit: ['src/**/*.test.js', 'src/**/*.spec.js'],
integration: ['tests/integration/**/*.test.js'],
e2e: ['tests/e2e/**/*.test.js']
},
coverage: {
enabled: true,
threshold: {
lines: 80,
functions: 85,
branches: 75,
statements: 80
},
exclude: [
'node_modules/**',
'dist/**',
'coverage/**',
'**/*.config.js',
'tests/fixtures/**'
]
},
parallel: {
enabled: true,
max_workers: 4
},
timeout: {
unit: 5000,
integration: 30000,
e2e: 60000
},
environment: {
NODE_ENV: 'test',
CI: 'true',
API_URL: 'http://localhost:3001',
DATABASE_URL: 'sqlite://memory'
},
notifications: {
on_failure: true,
on_success: false,
on_coverage_drop: true,
channels: ['email', 'slack']
}
};
const response = await fetch(`/api/testing/projects/${projectId}/settings`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
body: JSON.stringify(settings)
});
const result = await response.json();
console.log('CI 测试配置已更新:', result.updated_at);
return result;
};
// 使用示例
setupCITesting('proj_123');监控测试趋势
javascript
// 监控测试质量趋势
const monitorTestTrends = async (projectId) => {
const response = await fetch(`/api/testing/projects/${projectId}/statistics?period=month`);
const stats = await response.json();
console.log('📈 测试趋势分析 (最近一个月)');
console.log('='.repeat(50));
// 成功率趋势
const successRateTrend = stats.trends.success_rate;
const latestSuccessRate = successRateTrend[successRateTrend.length - 1].value;
const firstSuccessRate = successRateTrend[0].value;
const successRateChange = latestSuccessRate - firstSuccessRate;
console.log(`平均成功率: ${stats.summary.average_success_rate}%`);
console.log(`成功率变化: ${successRateChange > 0 ? '+' : ''}${successRateChange.toFixed(1)}%`);
// 覆盖率趋势
const coverageTrend = stats.trends.coverage;
const latestCoverage = coverageTrend[coverageTrend.length - 1].value;
const firstCoverage = coverageTrend[0].value;
const coverageChange = latestCoverage - firstCoverage;
console.log(`平均覆盖率: ${stats.summary.average_coverage}%`);
console.log(`覆盖率变化: ${coverageChange > 0 ? '+' : ''}${coverageChange.toFixed(1)}%`);
// 性能趋势
const durationTrend = stats.trends.duration;
const latestDuration = durationTrend[durationTrend.length - 1].value;
const firstDuration = durationTrend[0].value;
const durationChange = latestDuration - firstDuration;
console.log(`平均运行时间: ${stats.summary.average_duration}s`);
console.log(`运行时间变化: ${durationChange > 0 ? '+' : ''}${durationChange}s`);
// 不稳定测试
if (stats.flaky_tests.length > 0) {
console.log('\n⚠️ 不稳定的测试:');
stats.flaky_tests.forEach(test => {
console.log(` - ${test.name}: ${test.failure_rate}% 失败率`);
});
}
// 测试类型分析
console.log('\n📊 测试类型分析:');
Object.entries(stats.test_types).forEach(([type, data]) => {
console.log(` ${type}: ${data.count} 个测试, ${data.success_rate}% 成功率, 平均 ${data.average_duration}s`);
});
return stats;
};
// 使用示例
monitorTestTrends('proj_123');