Files
everything-is-suitable/everything-is-suitable-test/docs/plans/2026-03-07-test-suite-improvement.md
T
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

1178 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 测试套件改进计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 将测试套件从当前77.8%覆盖率提升到金融级90%-95%标准,建立完整的测试金字塔,实现全生命周期质量保障
**Architecture:** 采用分层测试策略,优先补充高优先级覆盖率缺口,建立稳定可执行的测试基础设施,逐步引入性能、安全和集成测试
**Tech Stack:** Python (pytest, coverage), Playwright (TypeScript), Spring Boot (Java), Maven, Docker, CI/CD
---
## 改进阶段划分
### 阶段1: 高优先级修复(1-2周)- 覆盖率提升至85%+
### 阶段2: 中期优化(1-2个月)- 建立完整测试金字塔
### 阶段3: 长期建设(3-6个月)- 达到金融级合规标准
---
## 阶段1: 高优先级修复(1-2周)
### Task 1: 补充main.py测试
**Files:**
- Create: `api/tests/unit/test_main.py`
- Test: `api/tests/unit/test_main.py`
**Step 1: 分析main.py功能**
Read: `api/src/apitest/main.py`
Expected: 识别CLI入口点、参数解析、主流程
**Step 2: Write failing tests**
```python
# api/tests/unit/test_main.py
import pytest
from unittest.mock import patch, MagicMock
from apitest.main import main
import sys
def test_main_with_no_arguments():
"""测试无参数时显示帮助信息"""
with patch('sys.argv', ['main']):
with patch('builtins.print') as mock_print:
main()
# 验证调用了print
assert mock_print.called
def test_main_with_valid_command():
"""测试有效命令执行"""
with patch('sys.argv', ['main', 'run', '--config', 'test.yaml']):
with patch('apitest.main.TestEngine') as mock_engine:
with patch('apitest.main.load_config') as mock_config:
mock_config.return_value = {'test': 'config'}
main()
# 验证创建了TestEngine
assert mock_engine.called
def test_main_with_invalid_command():
"""测试无效命令处理"""
with patch('sys.argv', ['main', 'invalid']):
with pytest.raises(SystemExit):
main()
def test_main_with_config_file_not_found():
"""测试配置文件不存在"""
with patch('sys.argv', ['main', 'run', '--config', 'nonexistent.yaml']):
with patch('builtins.open', side_effect=FileNotFoundError):
with pytest.raises(SystemExit):
main()
```
**Step 3: Run test to verify it fails**
Run: `cd api && python -m pytest tests/unit/test_main.py -v`
Expected: FAIL with "module 'apitest.main' not found" or import errors
**Step 4: Implement minimal main.py structure**
Read: `api/src/apitest/main.py`
If file is minimal, add basic structure:
```python
# api/src/apitest/main.py
import sys
from apitest.cli_module import CLICommand
def main():
"""主入口函数"""
if len(sys.argv) < 2:
print("Usage: python -m apitest.main <command> [options]")
print("Commands: run, test, report")
sys.exit(1)
command = sys.argv[1]
cli = CLICommand()
if command == 'run':
cli.run_tests()
elif command == 'test':
cli.run_specific_test()
elif command == 'report':
cli.generate_report()
else:
print(f"Unknown command: {command}")
sys.exit(1)
if __name__ == '__main__':
main()
```
**Step 5: Run test to verify it passes**
Run: `cd api && python -m pytest tests/unit/test_main.py -v`
Expected: PASS
**Step 6: Commit**
```bash
git add api/tests/unit/test_main.py api/src/apitest/main.py
git commit -m "test: add main.py unit tests and basic CLI structure"
```
---
### Task 2: 提升cli_module.py覆盖率到80%+
**Files:**
- Modify: `api/tests/unit/test_cli.py`
- Test: `api/tests/unit/test_cli.py`
**Step 1: 分析未覆盖代码行**
Run: `cd api && python -m pytest tests/unit/test_cli.py --cov=src/apitest/cli_module --cov-report=term-missing`
Expected: 识别未覆盖的代码行(52, 61-93, 96-100, 131, 134-136, 158, 160, 162, 164, 167-170, 196-198, 223
**Step 2: Write tests for missing branches**
```python
# api/tests/unit/test_cli.py - 补充测试
def test_cli_run_with_invalid_config():
"""测试无效配置文件"""
cli = CLICommand()
with pytest.raises(Exception):
cli.run_tests(config='invalid.yaml')
def test_cli_run_with_missing_test_cases():
"""测试缺少测试用例"""
cli = CLICommand()
with patch('os.path.exists', return_value=False):
with pytest.raises(FileNotFoundError):
cli.run_tests()
def test_cli_report_generation():
"""测试报告生成功能"""
cli = CLICommand()
with patch('apitest.cli_module.ReportManager') as mock_report:
cli.generate_report()
assert mock_report.generate.called
def test_cli_error_handling():
"""测试错误处理逻辑"""
cli = CLICommand()
with patch.object(cli, 'run_tests', side_effect=Exception("Test error")):
with pytest.raises(Exception):
cli.run_tests()
```
**Step 3: Run test to verify coverage improvement**
Run: `cd api && python -m pytest tests/unit/test_cli.py --cov=src/apitest/cli_module --cov-report=term-missing`
Expected: Coverage increases from 72.6% to 80%+
**Step 4: Commit**
```bash
git add api/tests/unit/test_cli.py
git commit -m "test: improve cli_module.py coverage to 80%+"
```
---
### Task 3: 修复API服务启动问题
**Files:**
- Modify: `everything-is-suitable-api/everything-is-suitable-app/src/main/resources/application.yml`
- Modify: `everything-is-suitable-api/everything-is-suitable-app/pom.xml`
- Test: Manual verification
**Step 1: 分析bean冲突原因**
Run: `cd everything-is-suitable-api && mvn dependency:tree | grep jacksonConfig`
Expected: 识别哪个模块定义了jacksonConfig bean
**Step 2: 检查Spring Boot配置**
Read: `everything-is-suitable-api/everything-is-suitable-app/src/main/resources/application.yml`
Look for bean configuration and component scanning
**Step 3: 解决bean名称冲突**
Option A: 重命名冲突的bean
```java
// everything-is-suitable-api/everything-is-suitable-base/src/main/java/.../JacksonConfig.java
@Configuration
public class BaseJacksonConfig { // 重命名
// configuration
}
```
Option B: 使用@Primary注解
```java
@Configuration
@Primary
public class AppJacksonConfig { // 标记为首选
// configuration
}
```
**Step 4: 验证服务启动**
Run: `cd everything-is-suitable-api/everything-is-suitable-app && mvn spring-boot:run -Dspring-boot.run.profiles=dev`
Expected: Service starts successfully on port 8080
**Step 5: Commit**
```bash
git add everything-is-suitable-api/
git commit -m "fix: resolve jacksonConfig bean name conflict"
```
---
### Task 4: 修复E2E测试模块引用问题
**Files:**
- Modify: `e2e/examples/admin-role-management.spec.ts`
- Modify: `e2e/examples/admin-user-management.spec.ts`
- Test: `e2e/integration/login-mock.spec.ts`
**Step 1: 分析fixtures路径错误**
Read: `e2e/examples/admin-role-management.spec.ts:1`
Expected: `import { test, expect } from './fixtures/test-fixtures';`
**Step 2: 修复import路径**
```typescript
// e2e/examples/admin-role-management.spec.ts
// 修改为正确的相对路径
import { test, expect } from '../fixtures/test-fixtures';
```
**Step 3: 验证所有测试文件**
Run: `cd e2e && grep -r "from './fixtures/test-fixtures'" examples/`
Expected: 找到所有需要修复的文件
**Step 4: 批量修复**
Run: `cd e2e && find examples/ -name "*.spec.ts" -exec sed -i '' "s|from './fixtures/test-fixtures'|from '../fixtures/test-fixtures'|g" {} \;`
**Step 5: 验证测试可执行**
Run: `cd e2e && ADMIN_BASE_URL=http://localhost:5173 npx playwright test examples/ --list`
Expected: No module import errors
**Step 6: Commit**
```bash
git add e2e/examples/
git commit -m "fix: correct fixtures import paths in example tests"
```
---
### Task 5: 建立测试环境管理脚本
**Files:**
- Create: `scripts/start-test-env.sh`
- Create: `scripts/stop-test-env.sh`
- Create: `scripts/check-services.sh`
**Step 1: 创建服务启动脚本**
```bash
# scripts/start-test-env.sh
#!/bin/bash
set -e
echo "========================================="
echo " 启动测试环境"
echo "========================================"
# 检查端口占用
check_port() {
local port=$1
if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null 2>&1; then
echo "端口 $port 已被占用"
return 1
fi
return 0
}
# 启动API服务
echo "----------------------------------------"
echo " 启动 API 服务..."
echo "----------------------------------------"
if check_port 8080; then
echo "API服务已在运行"
else
cd everything-is-suitable-api/everything-is-suitable-app
nohup mvn spring-boot:run -Dspring-boot.run.profiles=dev > /tmp/api.log 2>&1 &
echo "API服务启动中..."
sleep 30
fi
# 启动Admin服务
echo "----------------------------------------"
echo " 启动 Admin 服务..."
echo "----------------------------------------"
if check_port 5173; then
echo "Admin服务已在运行"
else
cd everything-is-suitable-admin
nohup npm run dev > /tmp/admin.log 2>&1 &
echo "Admin服务启动中..."
sleep 10
fi
# 验证服务健康
echo "----------------------------------------"
echo " 验证服务健康..."
echo "----------------------------------------"
bash scripts/check-services.sh
echo "========================================="
echo " ✅ 所有服务启动成功!"
echo "========================================="
```
**Step 2: 创建服务停止脚本**
```bash
# scripts/stop-test-env.sh
#!/bin/bash
set -e
echo "========================================="
echo " 停止测试环境"
echo "========================================"
# 停止API服务
echo "停止 API 服务..."
pkill -f "everything-is-suitable-app"
echo "API服务已停止"
# 停止Admin服务
echo "停止 Admin 服务..."
pkill -f "vite.*5173"
echo "Admin服务已停止"
echo "========================================="
echo " ✅ 所有服务已停止"
echo "========================================="
```
**Step 3: 创建服务检查脚本**
```bash
# scripts/check-services.sh
#!/bin/bash
set -e
echo "========================================="
echo " 服务状态检查"
echo "========================================="
# 检查API服务
echo "API 服务:"
if curl -s http://localhost:8080/api/health > /dev/null 2>&1; then
echo " ✅ 运行中 (http://localhost:8080/api/health)"
else
echo " ❌ 未运行"
fi
# 检查Admin服务
echo "Admin 服务:"
if curl -s http://localhost:5173 > /dev/null 2>&1; then
echo " ✅ 运行中 (http://localhost:5173)"
else
echo " ❌ 未运行"
fi
echo "========================================="
```
**Step 4: 添加执行权限**
Run: `chmod +x scripts/start-test-env.sh scripts/stop-test-env.sh scripts/check-services.sh`
**Step 5: 测试脚本**
Run: `bash scripts/check-services.sh`
Expected: 显示服务状态
**Step 6: Commit**
```bash
git add scripts/
git commit -m "feat: add test environment management scripts"
```
---
## 阶段2: 中期优化(1-2个月)
### Task 6: 增加集成测试覆盖
**Files:**
- Create: `api/tests/integration/`
- Create: `api/tests/integration/test_api_integration.py`
**Step 1: 设计集成测试场景**
```python
# api/tests/integration/test_api_integration.py
import pytest
import requests
from apitest.client.api_client import APIClient
from apitest.client.auth_manager import AuthManager
@pytest.fixture(scope="module")
def api_client():
"""API客户端fixture"""
return APIClient("http://localhost:8080")
@pytest.fixture(scope="module")
def auth_manager():
"""认证管理器fixture"""
return AuthManager(
"http://localhost:8080",
{"username": "admin", "password": "admin123"},
None
)
def test_api_integration_full_workflow(api_client, auth_manager):
"""测试完整API集成工作流"""
# 1. 登录
login_result = auth_manager.login()
assert login_result["data"]["token"]
# 2. 使用token访问受保护资源
api_client.set_auth_token(auth_manager._token)
result = api_client.get("/sys/user/list")
assert result["status_code"] == 200
# 3. 登出
auth_manager.logout()
assert auth_manager._token is None
```
**Step 2: 创建集成测试配置**
```python
# api/tests/integration/conftest.py
import pytest
def pytest_configure(config):
"""集成测试配置"""
config.addinivalue_marker(
"integration",
"标记为集成测试,需要真实服务"
)
```
**Step 3: 运行集成测试**
Run: `cd api && python -m pytest tests/integration/ -v -m integration`
Expected: PASS (需要服务运行)
**Step 4: Commit**
```bash
git add api/tests/integration/
git commit -m "test: add API integration tests"
```
---
### Task 7: 补充E2E业务流程测试
**Files:**
- Create: `e2e/integration/user-workflow.spec.ts`
- Create: `e2e/integration/role-workflow.spec.ts`
**Step 1: 设计用户管理工作流测试**
```typescript
// e2e/integration/user-workflow.spec.ts
import { test, expect } from '@playwright/test';
const BASE_URL = process.env.ADMIN_BASE_URL || 'http://localhost:5173';
test.describe('用户管理工作流E2E测试', () => {
test('完整用户生命周期', async ({ page }) => {
await page.goto(`${BASE_URL}/login`);
// 登录
await page.fill('[data-testid="username-input"]', 'admin');
await page.fill('[data-testid="password-input"]', 'admin123');
await page.click('[data-testid="login-button"]');
await expect(page).toHaveURL(/.*\//);
// 创建用户
await page.goto(`${BASE_URL}/system/user`);
await page.click('button:has-text("新增")');
await page.fill('[data-testid="username-input"]', 'testuser');
await page.fill('[data-testid="email-input"]', 'test@example.com');
await page.click('button:has-text("保存")');
await expect(page.locator('text=保存成功')).toBeVisible();
// 编辑用户
await page.click('td:has-text("testuser") button:has-text("编辑")');
await page.fill('[data-testid="email-input"]', 'updated@example.com');
await page.click('button:has-text("保存")');
await expect(page.locator('text=保存成功')).toBeVisible();
// 删除用户
await page.click('td:has-text("testuser") button:has-text("删除")');
await page.click('button:has-text("确认")');
await expect(page.locator('text=删除成功')).toBeVisible();
});
});
```
**Step 2: 运行工作流测试**
Run: `cd e2e && ADMIN_BASE_URL=http://localhost:5173 npx playwright test integration/user-workflow.spec.ts --headed`
Expected: PASS (需要完整服务)
**Step 3: Commit**
```bash
git add e2e/integration/
git commit -m "test: add user and role workflow E2E tests"
```
---
### Task 8: 建立测试数据管理
**Files:**
- Create: `api/tests/factories/test_data_factory.py`
- Modify: `api/tests/conftest.py`
**Step 1: 创建测试数据工厂**
```python
# api/tests/factories/test_data_factory.py
from faker import Faker
fake = Faker('zh_CN')
class TestDataFactory:
"""测试数据工厂"""
@staticmethod
def create_user():
"""创建测试用户数据"""
return {
"username": fake.user_name(),
"email": fake.email(),
"phone": fake.phone_number(),
"password": fake.password(length=12),
}
@staticmethod
def create_role():
"""创建测试角色数据"""
return {
"roleName": fake.job(),
"description": fake.sentence(),
"permissions": ["user:read", "user:write"],
}
@staticmethod
def create_menu():
"""创建测试菜单数据"""
return {
"menuName": fake.word(),
"menuType": "directory",
"path": f"/{fake.word()}",
"icon": fake.word(),
}
```
**Step 2: 集成到conftest**
```python
# api/tests/conftest.py
import pytest
from tests.factories.test_data_factory import TestDataFactory
@pytest.fixture
def test_user():
"""测试用户数据fixture"""
return TestDataFactory.create_user()
@pytest.fixture
def test_role():
"""测试角色数据fixture"""
return TestDataFactory.create_role()
```
**Step 3: 使用测试数据工厂**
```python
# 在测试中使用
def test_create_user_with_factory(test_user):
"""使用工厂创建测试用户"""
result = api_client.post("/sys/user", body=test_user)
assert result["status_code"] == 201
```
**Step 4: Commit**
```bash
git add api/tests/factories/
git commit -m "feat: add test data factory for better test maintainability"
```
---
## 阶段3: 长期建设(3-6个月)
### Task 9: 引入性能测试
**Files:**
- Create: `performance/load-test.jmx`
- Create: `performance/run-load-test.sh`
**Step 1: 创建JMeter负载测试计划**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2">
<hashTree>
<TestPlan guiclass="TestPlan" testclass="TestPlan" testname="API Load Test">
<elementProp name="TestPlan.user_define_classpath" elementType="TestPlan"
guiclass="TestPlan" testclass="TestPlan" testname="TestPlan.user_define_classpath">
<stringProp name="TestPlan.user_define_classpath" value=""/>
</elementProp>
<hashTree>
<ThreadGroup guiclass="ThreadGroup" testclass="ThreadGroup"
testname="Thread Group" sampler="LoopController">
<stringProp name="ThreadGroup.num_threads" value="100"/>
<stringProp name="ThreadGroup.ramp_time" value="10"/>
<stringProp name="ThreadGroup.duration" value="60"/>
<HTTPSamplerProxy guiclass="HTTPSamplerProxy" testclass="HTTPSamplerProxy"
testname="Login Request">
<stringProp name="HTTPSampler.domain" value="localhost"/>
<stringProp name="HTTPSampler.port" value="8080"/>
<stringProp name="HTTPSampler.path" value="/api/sys/auth/login"/>
<stringProp name="HTTPSampler.method" value="POST"/>
<elementProp name="HTTPsampler.Arguments" elementType="HTTPArguments">
<collectionProp name="HTTPsampler.Arguments.arguments">
<elementProp name="HTTPArgument" elementType="HTTPArgument">
<stringProp name="Argument.name" value="username"/>
<stringProp name="Argument.value" value="admin"/>
</elementProp>
<elementProp name="HTTPArgument" elementType="HTTPArgument">
<stringProp name="Argument.name" value="password"/>
<stringProp name="Argument.value" value="admin123"/>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
</ThreadGroup>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>
```
**Step 2: 创建性能测试执行脚本**
```bash
# performance/run-load-test.sh
#!/bin/bash
set -e
echo "========================================="
echo " 运行负载测试"
echo "========================================="
# 检查JMeter安装
if ! command -v jmeter &> /dev/null; then
echo "JMeter未安装,请先安装JMeter"
exit 1
fi
# 运行负载测试
jmeter -n -t performance/load-test.jmx \
-l performance/results.jtl \
-e -o performance/report \
-Jusers=100 \
-Jrampup=10 \
-Jduration=60
echo "========================================="
echo " 负载测试完成"
echo "========================================="
echo "报告位置: performance/report/index.html"
```
**Step 3: Commit**
```bash
git add performance/
git commit -m "feat: add performance testing with JMeter"
```
---
### Task 10: 添加安全测试
**Files:**
- Create: `security/security-test.py`
- Create: `security/run-security-scan.sh`
**Step 1: 创建安全测试脚本**
```python
# security/security-test.py
import requests
import pytest
class TestSecurity:
"""安全测试套件"""
BASE_URL = "http://localhost:8080"
def test_sql_injection_protection(self):
"""测试SQL注入防护"""
malicious_payloads = [
"' OR '1'='1",
"admin'--",
"' UNION SELECT * FROM users--",
]
for payload in malicious_payloads:
response = requests.post(
f"{self.BASE_URL}/api/sys/auth/login",
json={"username": payload, "password": "test"}
)
# 应该返回401或400,而不是500
assert response.status_code in [400, 401]
def test_xss_protection(self):
"""测试XSS防护"""
xss_payloads = [
"<script>alert('xss')</script>",
"<img src=x onerror=alert('xss')>",
"javascript:alert('xss')",
]
for payload in xss_payloads:
response = requests.post(
f"{self.BASE_URL}/api/sys/user",
json={"username": payload}
)
# 应该过滤或转义
assert response.status_code in [400, 403]
def test_authentication_bypass(self):
"""测试认证绕过"""
# 测试无token访问
response = requests.get(f"{self.BASE_URL}/api/sys/user/list")
assert response.status_code == 401
# 测试过期token
response = requests.get(
f"{self.BASE_URL}/api/sys/user/list",
headers={"Authorization": "Bearer expired_token"}
)
assert response.status_code == 401
def test_sensitive_data_exposure(self):
"""测试敏感数据暴露"""
# 测试错误响应不应包含敏感信息
response = requests.post(
f"{self.BASE_URL}/api/sys/auth/login",
json={"username": "wrong", "password": "wrong"}
)
assert response.status_code == 401
# 验证不暴露数据库错误、堆栈信息等
assert "database" not in response.text.lower()
assert "stack" not in response.text.lower()
```
**Step 2: 创建安全扫描脚本**
```bash
# security/run-security-scan.sh
#!/bin/bash
set -e
echo "========================================="
echo " 运行安全扫描"
echo "========================================="
# 检查OWASP ZAP安装
if ! command -v zap-cli &> /dev/null; then
echo "OWASP ZAP未安装,请先安装ZAP"
exit 1
fi
# 运行ZAP扫描
zap-cli quick-scan \
-t http://localhost:5173 \
-r security/zap-report.html \
-x
echo "========================================="
echo " 安全扫描完成"
echo "========================================="
echo "报告位置: security/zap-report.html"
```
**Step 3: Commit**
```bash
git add security/
git commit -m "feat: add security testing suite"
```
---
### Task 11: 实施AI辅助测试
**Files:**
- Create: `ai/test-generator.py`
- Create: `ai/defect-predictor.py`
**Step 1: 创建测试用例生成器**
```python
# ai/test-generator.py
import openai
from typing import List, Dict
class TestGenerator:
"""AI辅助测试用例生成器"""
def __init__(self, api_key: str):
self.client = openai.OpenAI(api_key=api_key)
def generate_test_cases(self, function_code: str) -> List[Dict]:
"""基于函数代码生成测试用例"""
prompt = f"""
基于以下函数代码,生成全面的测试用例:
{function_code}
要求:
1. 生成正常路径测试
2. 生成边界条件测试
3. 生成异常情况测试
4. 每个测试用例包含:测试名称、输入、预期输出
返回JSON格式的测试用例列表。
"""
response = self.client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.7
)
content = response.choices[0].message.content
return eval(content) # 简化,实际应使用JSON解析
def generate_test_code(self, test_case: Dict) -> str:
"""生成测试代码"""
prompt = f"""
基于以下测试用例,生成pytest测试代码:
测试名称: {test_case['name']}
输入: {test_case['input']}
预期输出: {test_case['expected']}
要求:
1. 使用pytest框架
2. 包含适当的断言
3. 添加必要的mock
"""
response = self.client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.3
)
return response.choices[0].message.content
```
**Step 2: 创建缺陷预测器**
```python
# ai/defect-predictor.py
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
class DefectPredictor:
"""基于历史数据的缺陷预测器"""
def __init__(self):
self.model = RandomForestClassifier(n_estimators=100)
self.vectorizer = TfidfVectorizer(max_features=1000)
def train(self, historical_data: pd.DataFrame):
"""训练模型"""
X = self.vectorizer.fit_transform(historical_data['code_changes'])
y = historical_data['has_defect']
self.model.fit(X, y)
def predict(self, code_changes: str) -> float:
"""预测缺陷概率"""
X = self.vectorizer.transform([code_changes])
probability = self.model.predict_proba(X)[0][1]
return probability
def get_risk_level(self, probability: float) -> str:
"""获取风险等级"""
if probability > 0.7:
return "高风险"
elif probability > 0.4:
return "中风险"
else:
return "低风险"
```
**Step 3: Commit**
```bash
git add ai/
git commit -m "feat: add AI-assisted testing tools"
```
---
### Task 12: 建立CI/CD集成
**Files:**
- Create: `.github/workflows/test.yml`
- Create: `.github/workflows/quality-gate.yml`
**Step 1: 创建测试工作流**
```yaml
# .github/workflows/test.yml
name: Test Suite
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.13'
- name: Install dependencies
run: |
cd everything-is-suitable-test/api
pip install -r requirements.txt
- name: Run API tests
run: |
cd everything-is-suitable-test/api
python -m pytest tests/ --cov=src/apitest --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./everything-is-suitable-test/api/coverage.xml
- name: Check coverage threshold
run: |
coverage=$(python -c "import json; print(json.load(open('coverage.json'))['totals']['percent_covered'])")
if (( $(echo "$coverage < 85" | bc -l) )); then
echo "Coverage $coverage% is below threshold 85%"
exit 1
fi
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: |
cd everything-is-suitable-test/e2e
npm ci
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run E2E tests
run: |
cd everything-is-suitable-test/e2e
npx playwright test
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: everything-is-suitable-test/e2e/playwright-report/
```
**Step 2: 创建质量门禁工作流**
```yaml
# .github/workflows/quality-gate.yml
name: Quality Gate
on:
pull_request:
branches: [ main ]
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run linting
run: |
cd everything-is-suitable-test/api
flake8 src/apitest --max-line-length=100
- name: Run type checking
run: |
cd everything-is-suitable-test/api
mypy src/apitest --strict
- name: Check coverage
run: |
cd everything-is-suitable-test/api
python -m pytest tests/ --cov=src/apitest --cov-fail-under=85
- name: Security scan
run: |
bandit -r src/apitest -f json -o security-report.json
- name: Upload reports
uses: actions/upload-artifact@v3
with:
name: quality-reports
path: |
everything-is-suitable-test/api/security-report.json
```
**Step 3: Commit**
```bash
git add .github/workflows/
git commit -m "ci: add CI/CD pipelines with quality gates"
```
---
## 执行检查清单
### 阶段1完成标准
- [ ] main.py测试覆盖率 > 80%
- [ ] cli_module.py测试覆盖率 > 80%
- [ ] 整体API测试覆盖率 > 85%
- [ ] API服务可正常启动
- [ ] 所有E2E测试可执行
- [ ] 测试环境管理脚本可用
### 阶段2完成标准
- [ ] 集成测试覆盖核心业务流程
- [ ] E2E测试覆盖完整用户场景
- [ ] 测试数据工厂投入使用
- [ ] 测试类型分布均衡
### 阶段3完成标准
- [ ] 性能测试可执行
- [ ] 安全测试可执行
- [ ] AI辅助工具可用
- [ ] CI/CD流水线运行
- [ ] 质量门禁生效
- [ ] 整体覆盖率 > 90%
---
## 风险与缓解
### 风险1: API服务bean冲突
**缓解**: 优先解决Task 3,使用@Primary注解或重命名bean
### 风险2: E2E测试依赖后端
**缓解**: 使用Mock测试先行,真实后端测试作为补充
### 风险3: 性能测试环境要求
**缓解**: 使用轻量级负载测试,避免影响开发环境
### 风险4: AI工具成本
**缓解**: 使用开源模型或限制API调用次数
---
## 成功指标
### 阶段1指标
- 整体覆盖率: 77.8% → 85%+
- 测试通过率: 100% (保持)
- E2E可执行性: 8/87 → 87/87
### 阶段2指标
- 集成测试: 0 → 20+
- E2E业务流程: 8 → 30+
- 测试数据工厂: 0 → 1
### 阶段3指标
- 性能测试: 0 → 1个套件
- 安全测试: 0 → 1个套件
- AI辅助工具: 0 → 2个工具
- CI/CD: 0 → 2个流水线
- 整体覆盖率: 85% → 90%+
---
**计划创建时间**: 2026-03-07
**计划创建人**: 张翔(资深金融级高级自动化测试工程师)
**预计完成时间**: 6个月
**执行方法**: TDD + 频繁提交 + 持续验证