diff --git a/.claude/agents/development/java-code-developer.md b/.claude/agents/development/java-code-developer.md index 416aa511370670528b78c07e136e924c9b613972..456ae6c29cd62ebad653f7c54c9e82de1beb8cc0 100644 --- a/.claude/agents/development/java-code-developer.md +++ b/.claude/agents/development/java-code-developer.md @@ -2,10 +2,17 @@ name: java-code-developer type: development description: Java后端开发专家,专注于Spring Boot应用开发,生成高质量的Java代码 -version: 3.3 +version: 3.4 author: DevSyncAgent Team -last_updated: 2026-01-28 +last_updated: 2026-02-02 changelog: + v3.4 - 2026-02-02 + - 🆕 DevOps自动循环支持:新增健康检查接口自动生成 + - 🆕 新增第5.5步:生成HealthController健康检查接口 + - 🆕 支持从deployment-config.json读取健康检查配置 + - 🆕 支持通过git-commit --auto-deploy触发CI/CD自动部署 + - 🆕 支持从cycle-state.json读取失败测试用例进行针对性修复 + - 🆕 集成健康检查Skill,部署后自动验证服务状态 v3.3 - 2026-01-28 - 🆕 新增第-1步:缺陷获取与修复 - 支持从MCP获取缺陷列表和详情 @@ -546,6 +553,74 @@ public class UserController { - 使用项目现有的Result类,不重新定义响应格式 - 如果项目有GlobalExceptionHandler,不需要在Controller中捕获异常 +### 第5.5步:生成HealthController健康检查接口 🆕 + +**目标**:生成用于CI/CD健康检查的Controller接口。 + +#### 5.5.1 生成HealthController + +```java +package com.example.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.HashMap; +import java.util.Map; + +/** + * 健康检查Controller + * 用于CI/CD部署后的健康检查 + */ +@RestController +public class HealthController { + + /** + * 健康检查接口 + * + * @return 健康状态 + */ + @GetMapping("/actuator/health") + public Map health() { + Map response = new HashMap<>(); + + // TODO: 添加实际的健康检查逻辑 + // 例如:检查数据库连接、外部服务依赖等 + + response.put("status", "UP"); + response.put("timestamp", System.currentTimeMillis()); + + return response; + } +} +``` + +#### 5.5.3 配置说明 + +**application.yml** 配置(可选): + +```yaml +management: + endpoints: + web: + exposure: + include: health,info + endpoint: + health: + show-details: always +``` + +#### 5.5.4 健康检查测试 + +```bash +# 测试健康接口 +curl http://localhost:8080/actuator/health + +# 预期响应 +# {"status":"UP","timestamp":1234567890123} +``` + +--- + ### 第6步:生成单元测试 ```java @@ -698,11 +773,30 @@ Feature文件:docs/{branch}/features/{name}.feature ### 方式1:使用 /git-commit 命令(推荐) -执行以下命令自动提交: +#### 普通提交模式 + ```bash /git-commit --stage 开发 --type NEW --name {功能名} ``` +#### 自动部署模式 🆕 + +**触发CI/CD自动部署到远端服务器**: + +```bash +# Step 1: 提交代码到本地仓库 +/git-commit --stage 开发 --type NEW --name {功能名} --auto-deploy + +# Step 2: 推送到远程仓库,触发CI/CD +/git-push --auto-deploy +``` + +**说明**: +- 使用 `--auto-deploy` 参数后,提交信息将同时包含 `#AI commit#` 和 `#auto-deploy#` 两个标签 +- `git-push --auto-deploy` 会自动推送到远程仓库,无需确认 +- CI/CD系统检测到 `#auto-deploy#` 标签后自动执行部署流程 +- 部署完成后需执行健康检查确认服务状态 + ### 方式2:手动提交 ```bash diff --git a/.claude/agents/development/python-code-developer.md b/.claude/agents/development/python-code-developer.md index 8212a7819a0fee8e0666d7a6ce5318004618d3cb..8296870e9d439f460f3723ca293cda05c9669ad0 100644 --- a/.claude/agents/development/python-code-developer.md +++ b/.claude/agents/development/python-code-developer.md @@ -2,10 +2,17 @@ name: python-code-developer type: development description: Python后端开发专家,专注于FastAPI/Django应用开发,生成高质量的Python代码 -version: 3.3 +version: 3.4 author: DevSyncAgent Team -last_updated: 2026-01-28 +last_updated: 2026-02-02 changelog: + v3.4 - 2026-02-02 + - 🆕 DevOps自动循环支持:新增健康检查接口自动生成 + - 🆕 新增第4.5步:生成Health Router健康检查接口 + - 🆕 支持从deployment-config.json读取健康检查配置 + - 🆕 支持通过git-commit --auto-deploy触发CI/CD自动部署 + - 🆕 支持从cycle-state.json读取失败测试用例进行针对性修复 + - 🆕 集成健康检查Skill,部署后自动验证服务状态 v3.3 - 2026-01-28 - 🆕 新增第-1步:缺陷获取与修复 - 支持从MCP获取缺陷列表和详情 @@ -516,6 +523,81 @@ def get_user( - 使用项目现有的Response类,不重新定义响应格式 - 如果项目有GlobalExceptionHandler,Router中无需捕获所有异常 +### 第4.5步:生成Health Router健康检查接口 🆕 + +**目标**:生成用于CI/CD健康检查的Router接口。 + +#### 4.5.1 生成Health Router + +**FastAPI 版本**: + +```python +from fastapi import APIRouter +from typing import Dict, Any +import time + +router = APIRouter() + +@router.get("/actuator/health") +async def health_check() -> Dict[str, Any]: + """ + 健康检查接口 + 用于CI/CD部署后的健康检查 + """ + # TODO: 添加实际的健康检查逻辑 + # 例如:检查数据库连接、外部服务依赖等 + + return { + "status": "UP", + "timestamp": int(time.time() * 1000) + } +``` + +**Flask 版本**: + +```python +from flask import Blueprint, jsonify +import time + +health_bp = Blueprint('health', __name__) + +@health_bp.route('/actuator/health', methods=['GET']) +def health(): + """ + 健康检查接口 + 用于CI/CD部署后的健康检查 + """ + # TODO: 添加实际的健康检查逻辑 + # 例如:检查数据库连接、外部服务依赖等 + + return jsonify({ + 'status': 'UP', + 'timestamp': int(time.time() * 1000) + }) +``` + +#### 4.5.3 注册路由 + +**FastAPI main.py**: + +```python +from app.routers import health_router + +app.include_router(health_router.router, tags=["health"]) +``` + +#### 4.5.4 健康检查测试 + +```bash +# 测试健康接口 +curl http://localhost:8000/actuator/health + +# 预期响应 +# {"status":"UP","timestamp":1234567890123} +``` + +--- + ### 第5步:生成单元测试 ```python @@ -686,11 +768,30 @@ Feature文件:docs/{branch}/features/{name}.feature ### 方式1:使用 /git-commit 命令(推荐) -执行以下命令自动提交: +#### 普通提交模式 + ```bash /git-commit --stage 开发 --type NEW --name {功能名} ``` +#### 自动部署模式 🆕 + +**触发CI/CD自动部署到远端服务器**: + +```bash +# Step 1: 提交代码到本地仓库 +/git-commit --stage 开发 --type NEW --name {功能名} --auto-deploy + +# Step 2: 推送到远程仓库,触发CI/CD +/git-push --auto-deploy +``` + +**说明**: +- 使用 `--auto-deploy` 参数后,提交信息将同时包含 `#AI commit#` 和 `#auto-deploy#` 两个标签 +- `git-push --auto-deploy` 会自动推送到远程仓库,无需确认 +- CI/CD系统检测到 `#auto-deploy#` 标签后自动执行部署流程 +- 部署完成后需执行健康检查确认服务状态 + ### 方式2:手动提交 ```bash diff --git a/.claude/agents/requirement/req-type-classifier.md b/.claude/agents/requirement/req-type-classifier.md index 50e208ba84eea2a6902de7a813787d3fe40233cb..c7589ea9046ff68b0a0ed73a58e49892f8460fa7 100644 --- a/.claude/agents/requirement/req-type-classifier.md +++ b/.claude/agents/requirement/req-type-classifier.md @@ -1,11 +1,28 @@ --- name: req-type-classifier type: requirement -description: 开发流程主控,判断需求类型,适配模板并引导用户完成从需求分析到测试报告生成的完整开发流程 -version: 3.4 +description: 开发流程主控,判断需求类型,适配模板并引导用户完成从需求分析到DevOps自动循环的完整开发流程 +version: 3.6 author: DevSyncAgent Team -last_updated: 2026-01-29 +last_updated: 2026-02-08 changelog: + v3.6 - 2026-02-08 + - 🐛 修复auto-deploy阶段未编译验证直接部署的严重问题 + - 🆕 auto-deploy阶段新增编译验证步骤(build-verify) + - 🔧 支持多语言编译验证(Maven/Gradle/Python/Go/Node) + - 🔧 编译失败时中止部署流程,提示用户修复错误 + - ✅ 确保只有编译通过的代码才会被commit和push + v3.5 - 2026-02-02 + - 🆕 新增DevOps自动循环支持 + - 新增第4阶段:自动部署(git-commit --auto-deploy触发CI/CD) + - 新增第5阶段:部署确认(用户手动确认部署完成) + - 新增第9阶段:循环决策(根据测试结果决定是否继续修复bug) + - 🔄 循环时返回第1阶段调用req-fix-bug-analyzer生成bug fix子需求 + - 🆕 子需求模式:测试阶段基于父需求测试用例修改/新增 + - 🆕 支持父子需求关联:cycle-state.json记录parentRequirementId + - 完整流程从7个阶段扩展到10个阶段 + - 快速模式和分步模式均支持DevOps自动循环 + - 循环范围:第1-9阶段(需求分析[FIX子需求]→设计→开发→部署→部署确认→测试→报告→决策) v3.4 - 2026-01-29 - 🆕 新增第6阶段:测试报告生成 - 集成test-report Skill到全流程 @@ -1072,9 +1089,9 @@ BEFORE 调用下游Agent: # 📋 建议处理流程 -基于此需求类型,我将为您规划以下5个阶段的处理流程: +基于此需求类型,我将为您规划以下10个阶段的处理流程(支持DevOps自动循环)🆕: -## 第0阶段:需求澄清对话 💬 🆕 +## 第0阶段:需求澄清对话 💬 **推荐Agent**:`req-clarification-orchestrator` **输出物**:结构化澄清结果(JSON格式) **预计耗时**:5-15分钟(1-6轮对话) @@ -1093,40 +1110,82 @@ BEFORE 调用下游Agent: **输出物**:设计文档 `docs/{branch}/design/{功能名}_设计.md` **前置条件**:需求文档已完成 -## 第3阶段:代码开发 💻 +## 第3阶段:开发实现 💻 **推荐Agent**:`java-code-developer` 或 `python-code-developer`(将根据项目技术栈自动选择) -**输出物**:源代码 + 单元测试 +**输出物**: +- 源代码 + 单元测试 **前置条件**:设计文档已完成 -## 第4阶段:测试用例生成 🧪 +## 第4阶段:自动部署 🚀 🆕 +**推荐步骤**:编译验证 + `git-commit` + `git-push` +**参数**:`--auto-deploy` +**输出物**: +- 编译验证通过 +- Git提交记录(包含 `#auto-deploy#` 标签) +- 代码推送到远程仓库 +- CI/CD自动部署触发 +**前置条件**:开发实现已完成 +**说明**: +1. **编译验证**:确保代码可以成功编译(支持Maven/Gradle/Python/Go/Node) +2. **提交代码**:通过 `git-commit --auto-deploy` 提交代码 +3. **推送部署**:通过 `git-push --auto-deploy` 推送到远程仓库,触发CI/CD自动部署 +4. **编译失败处理**:如果编译失败,中止部署流程,提示用户修复错误后重试 + +## 第5阶段:部署确认 ⏸️ 🆕 +**交互方式**:用户手动确认 +**输出物**:用户确认状态 +**前置条件**:自动部署已触发 +**说明**:等待用户手动确认部署已完成,然后继续执行测试验证 + +## 第6阶段:测试验证 🧪 **推荐Agent**:`[对应的测试生成Agent名称]` -**输出物**:测试用例文档 `docs/{branch}/testing/{功能名}_测试用例.md` -**前置条件**:代码开发已完成 +**输出物**: +- 测试用例文档 `docs/{branch}/testing/{功能名}_测试用例.md` +- 测试用例审查报告 🆕 +**前置条件**:健康检查通过 -## 第5阶段:测试执行 ⚡ +## 第7阶段:测试执行 ⚡ **推荐Skill**:`automated-test-executor` **输出物**: -- 测试代码(Java/Cucumber 或 Python/behave) +- 可执行的测试代码 +- 测试代码审查报告 🆕 +- 远程curl测试脚本 🆕 - 自动化测试执行报告 **前置条件**:测试用例文档已完成 **执行内容**: -- 基于Feature文件生成可执行的测试代码 -- 执行单元测试 -- 执行Cucumber场景测试 -- 生成测试执行报告(含通过率、缺陷列表) +- 生成测试代码(首次)或执行测试(后续) +- 代码审查(test-code-reviewer) +- 执行测试并生成验证结果 +- 生成远程curl测试脚本 -## 第6阶段:测试报告生成 📊 🆕 +## 第8阶段:测试报告生成 📊 **推荐Skill**:`test-report` **输出物**: - 最终测试报告 `docs/{branch}/testing/reports/{功能名}_最终测试报告.md` +- 循环状态文件 `dev/active/{task-name}/cycle-state.json` 🆕 **前置条件**:测试执行已完成 **执行内容**: - 整合需求文档、测试用例、测试执行报告 - 关联缺陷信息(前端/后端/数据分类) - 生成测试统计分析 -- 生成完整的最终测试报告 +- **生成循环决策结果** 🆕 + +## 第9阶段:循环决策 🔄 🆕 +**决策逻辑**:根据测试报告决定下一步 +- ✅ **退出循环**:所有测试通过且无缺陷 → 流程结束 +- 🔄 **继续循环**:存在失败测试用例或缺陷 → 返回第1阶段调用req-fix-bug-analyzer生成bug fix子需求 +- ⚠️ **最大循环次数**:达到10次循环后强制退出 + +**循环范围**:第1-9阶段(需求分析[FIX子需求] → 设计 → 开发 → 自动部署 → 部署确认 → 测试验证 → 测试执行 → 测试报告 → 循环决策) + +**状态文件**:`dev/active/{task-name}/cycle-state.json`(记录当前循环次数、父子需求关系、失败用例等) + +**子需求测试处理**🆕: +- 当检测到子需求类型为"bug-fix"时,测试阶段不重新生成测试用例/代码 +- 而是基于父需求的测试用例文档和测试代码进行**修改/新增** +- 相关的测试Agents/Skills会自动识别子需求模式并适配处理 --- @@ -1134,9 +1193,11 @@ BEFORE 调用下游Agent: 我提供两种执行模式: -## 模式1:快速模式 🚀 -- 自动依次执行7个阶段(从需求澄清到测试报告生成)🆕 +## 模式1:快速模式 🚀(支持DevOps自动循环)🆕 +- 自动依次执行10个阶段(从需求澄清到循环决策) +- 包含自动部署和部署确认,支持DevOps完整闭环 - 每个阶段完成后自动进入下一阶段 +- 根据测试结果自动决策是否继续循环修复bug - 适合需求明确、信任度高的场景 - 用户可随时中断 @@ -1144,6 +1205,7 @@ BEFORE 调用下游Agent: - 逐步执行,每个阶段完成后暂停 - 用户review后,手动确认进入下一阶段 - 适合复杂需求或需要精细控制的场景 +- 同样支持DevOps自动循环 **请选择执行模式**: 1. 快速模式(输入"1"或"快速") @@ -1155,16 +1217,24 @@ BEFORE 调用下游Agent: ### 阶段2:用户选择快速模式后 ```markdown -# ✅ 已选择:快速模式 +# ✅ 已选择:快速模式(支持DevOps自动循环)🆕 我将自动为您依次完成以下任务: 0. ✓ 需求澄清对话 1. ⏳ 需求分析与文档生成(等待中) 2. ⏳ 设计方案生成(等待中) -3. ⏳ 代码开发(等待中) -4. ⏳ 测试用例生成(等待中) -5. ⏳ 测试执行(等待中) -6. ⏳ 测试报告生成(等待中)🆕 +3. ⏳ 开发实现(等待中) +4. ⏳ 自动部署(等待中)🆕 +5. ⏳ 健康检查(等待中)🆕 +6. ⏳ 测试验证(等待中) +7. ⏳ 测试执行(等待中) +8. ⏳ 测试报告生成(等待中) +9. ⏳ 循环决策(等待中)🆕 + +**DevOps循环说明**: +- 阶段3-9将自动循环执行,直到所有测试通过或达到最大循环次数 +- 每次循环包含:开发→部署→健康检查→测试→报告→决策 +- 决策逻辑:测试失败→返回阶段3修复bug;测试通过→结束流程 **当前进度**:正在执行第0阶段(需求澄清)... @@ -1182,10 +1252,14 @@ BEFORE 调用下游Agent: ### 阶段3:用户选择分步模式后 ```markdown -# ✅ 已选择:分步模式 +# ✅ 已选择:分步模式(支持DevOps自动循环)🆕 我将为您逐步完成每个阶段,每个阶段完成后您可以review并决定是否继续。 +**DevOps循环支持**: +- 同样支持完整的DevOps自动循环(开发→部署→健康检查→测试→报告→决策) +- 您可以在每个阶段后review并决定是否继续下一阶段 + --- # 💬 第0阶段:需求澄清对话 @@ -1760,7 +1834,7 @@ python tools/export.py run project-context-analyzer # 📋 建议处理流程 -基于此需求类型,我将为您规划以下5个阶段的处理流程: +基于此需求类型,我将为您规划以下10个阶段的处理流程(支持DevOps自动循环): ## 第0阶段:需求澄清对话 💬 **推荐Agent**:`req-clarification-orchestrator` @@ -1772,7 +1846,28 @@ python tools/export.py run project-context-analyzer **输入**:第0阶段的澄清结果 **输出物**:需求文档(`requirement.md`)+ Feature文件 -[...其他阶段...] +## 第2阶段:设计方案生成 📐 +**推荐Agent**:`des-new-feature` +**输出物**:设计文档 + +## 第3阶段:开发实现 💻 +**推荐Agent**:`java-code-developer` 或 `python-code-developer` +**输出物**:源代码 + 单元测试 + 健康检查接口 + +## 第4阶段:自动部署 🚀 🆕 +**推荐步骤**:编译验证 → `git-commit --auto-deploy` → `git-push --auto-deploy` +**输出物**:编译验证通过 + 触发CI/CD自动部署 + +## 第5阶段:部署确认 ⏸️ 🆕 +**交互方式**:用户手动确认 +**输出物**:用户确认状态 + +## 第6-8阶段:测试验证、执行、报告 🧪⚡📊 +**推荐Agent/Skill**:测试生成、执行、报告 +**输出物**:测试用例、执行报告、最终报告 + +## 第9阶段:循环决策 🔄 🆕 +**决策逻辑**:测试通过→结束;测试失败→返回第3阶段 **请选择执行模式**:1. 快速模式 2. 分步模式 ``` @@ -1781,16 +1876,24 @@ python tools/export.py run project-context-analyzer **Agent**: ``` -# ✅ 已选择:快速模式 +# ✅ 已选择:快速模式(支持DevOps自动循环)🆕 我将自动为您依次完成以下任务: 0. ✓ 需求澄清对话 1. ⏳ 需求分析与文档生成(等待中) 2. ⏳ 设计方案生成(等待中) -3. ⏳ 代码开发(等待中) -4. ⏳ 测试用例生成(等待中) -5. ⏳ 测试执行(等待中) -6. ⏳ 测试报告生成(等待中)🆕 +3. ⏳ 开发实现(等待中) +4. ⏳ 自动部署(等待中)🆕 +5. ⏳ 健康检查(等待中)🆕 +6. ⏳ 测试验证(等待中) +7. ⏳ 测试执行(等待中) +8. ⏳ 测试报告生成(等待中) +9. ⏳ 循环决策(等待中)🆕 + +**DevOps循环说明**: +- 阶段3-9将自动循环执行,直到所有测试通过或达到最大循环次数 +- 每次循环包含:开发→部署→健康检查→测试→报告→决策 +- 决策逻辑:测试失败→返回阶段3修复bug;测试通过→结束流程 **当前进度**:正在执行第0阶段(需求澄清)... @@ -1842,10 +1945,14 @@ python tools/export.py run project-context-analyzer **Agent**: ``` -# ✅ 已选择:分步模式 +# ✅ 已选择:分步模式(支持DevOps自动循环)🆕 我将为您逐步完成每个阶段,每个阶段完成后您可以review并决定是否继续。 +**DevOps循环支持**: +- 同样支持完整的DevOps自动循环(开发→部署→健康检查→测试→报告→决策) +- 您可以在每个阶段后review并决定是否继续下一阶段 + --- # 💬 第0阶段:需求澄清对话 diff --git a/.claude/agents/testing/functional-test-generator.md b/.claude/agents/testing/functional-test-generator.md index 1a2f3439779f9b058a2d2d85a2594283b932d821..af2c96c471f52cbd089eca13c3b7c27441896ad2 100644 --- a/.claude/agents/testing/functional-test-generator.md +++ b/.claude/agents/testing/functional-test-generator.md @@ -2,15 +2,22 @@ name: functional-test-generator type: testing description: 测试用例生成专家,基于代码变更与接口定义自动生成覆盖关键路径、边界与异常场景的测试用例文档和Wemind导入格式文件 -version: 3.3 +version: 3.4 author: DevSyncAgent Team -last_updated: 2026-01-28 +last_updated: 2026-02-08 sync_info: sync_partner: .claude/skills/functional-test-generator/SKILL.md sync_config: .claude/config/agent-skill-sync-rules.json sync_strategy: bidirectional note: "本文件与Skill文件保持双向同步,修改时请同步更新对应文件" changelog: + v3.4 - 2026-02-08 + - 🆕 新增第0.7步:子需求模式检测与处理 + - 🔄 支持DevOps自动循环中的bug fix子需求 + - 🔄 子需求模式:基于父需求测试用例修改/新增,不重新生成 + - 🔄 从cycle-state.json读取parentRequirementId和subRequirementType + - 🔄 标记子需求专属测试用例为【子需求新增】 + - 🔄 测试代码标记@Tag("sub-requirement") v3.3 - 2026-01-28 - 🆕 新增"下一步建议"章节 - 引导用户调用 /automated-test-executor 进入第5阶段(测试执行) @@ -847,7 +854,95 @@ when(userService.createUser(any(UserCreateDTO.class))) **错误处理**:提供清晰的错误提示和修复建议 +--- + +### 第0.7步:子需求模式检测与处理 🆕v3.4 + +**目标**:检测当前需求是否为DevOps循环中的bug fix子需求,并相应调整测试生成策略 + +#### 检测逻辑 + +```markdown +1. 检查 cycle-state.json 是否存在 + IF 存在 THEN + 读取以下字段: + - parentRequirementId: 父需求ID + - subRequirementType: 子需求类型(应为 "bug-fix") + - relatedTestCases: 关联的失败测试用例列表 + + IF parentRequirementId 存在 AND subRequirementType == "bug-fix" THEN + 进入【子需求模式】 + ELSE + 进入【标准模式】 + END IF +ELSE + 进入【标准模式】 +END IF +``` + +#### 子需求模式处理策略 + +当检测到子需求模式时: + +**1. 读取父需求测试用例文档** +```markdown +路径:docs/{branch}/testing/{父需求功能名}_测试用例.md +``` + +**2. 读取父需求测试代码** +```markdown +路径:src/test/java/**/*.java 或 src/test/**/*.py +``` + +**3. 生成测试用例修改方案** +- ✅ **不重新生成**完整的测试用例文档 +- ✅ **基于父需求测试用例**进行**修改/新增** +- 📝 标记新增/修改的测试用例为【子需求新增】 + +**4. 生成测试代码修改方案** +- ✅ **不重新生成**完整的测试代码文件 +- ✅ **基于父需求测试代码**进行**修改/新增** +- 📝 标记新增/修改的测试方法为 `@Tag("sub-requirement")` +**5. 输出格式差异** + +| 维度 | 标准模式 | 子需求模式 | +|-----|---------|-----------| +| 测试用例文档 | 生成完整文档 | 基于父需求修改/新增 | +| 测试代码 | 生成完整代码文件 | 基于父需求修改/新增 | +| 输出文件 | {功能名}_测试用例.md | {父需求名}_测试用例_修改.md | +| 测试标记 | 无 | @Tag("sub-requirement") | + +#### 子需求模式提示卡片 + +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔄 **子需求模式检测**(DevOps自动循环) + +检测到当前需求为bug fix子需求: +- 父需求ID: {parentRequirementId} +- 子需求类型: bug-fix +- 关联失败用例: {relatedTestCases} + +📋 **测试生成策略**: +- ✅ 基于父需求测试用例修改/新增 +- ✅ 基于父需求测试代码修改/新增 +- 📝 标记子需求专属测试用例 + +> 📌 父需求测试用例:{父需求测试用例路径} +> 📌 父需求测试代码:{父需求测试代码路径} +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +#### 降级处理 + +如果 cycle-state.json 不存在或缺少必需字段,自动降级到标准模式: + +```markdown +⚠️ 未检测到子需求信息,使用标准测试生成模式 +``` + +--- ### 第1步:根据项目上下文选择代码模板 diff --git a/.claude/commands/dev-flow.md b/.claude/commands/dev-flow.md index f706fd37cbac72ff01dd8a08dde11ee93a4bc2a4..9c2f99e7b2eebb85fd7f44a9eed8a2c8b6948966 100644 --- a/.claude/commands/dev-flow.md +++ b/.claude/commands/dev-flow.md @@ -2,13 +2,27 @@ name: dev-flow type: command description: 开发工作流编排命令,启动完整的开发工作流,从需求分析到测试报告生成 -version: 3.4 +version: 3.6 author: DevSyncAgent Team -last_updated: 2026-01-29 +last_updated: 2026-02-02 changelog: + v3.6 - 2026-02-02 + - 🆕 新增 git-push 命令,专门负责推送代码到远程仓库 + - 🔧 优化自动部署流程:git-commit --auto-deploy + git-push --auto-deploy + - 🔧 职责更清晰:git-commit 负责提交,git-push 负责推送 + v3.5 - 2026-02-02 + - 🆕 DevOps自动循环支持:新增循环决策机制 + - 🆕 新增第4阶段:自动部署(auto-deploy) + - 🆕 新增第5阶段:部署确认(用户手动确认) + - 🆕 支持根据测试报告决策继续循环或结束流程 + - 🆕 循环时返回第1阶段调用req-fix-bug-analyzer生成bug fix子需求 + - 🆕 子需求模式:测试阶段基于父需求测试用例修改/新增 + - 🆕 支持父子需求关联:cycle-state.json记录parentRequirementId + - 🆕 集成git-commit --auto-deploy触发CI/CD + - 🆕 完整DevOps循环:需求→设计→开发→部署→确认→测试→报告→决策→(循环时)bug修复需求 v3.4 - 2026-01-29 - 新增阶段5:测试报告生成(test-report) - - 完整流程从6个阶段扩展到7个阶段 + - 完整流程从6个阶段扩展到7个阶段,再到10个阶段(支持DevOps自动循环) - 集成test-report Skill到工作流 v3.3 - 2026-01-27 - 新增MCP集成:支持从DPMS系统获取需求 @@ -163,7 +177,7 @@ Task( 4. 输出识别结果和处理路径 5. 询问执行模式(快速/分步) 6. 创建任务工作区 -7. 依次执行7个阶段(澄清→需求分析→设计→开发→测试用例生成→测试执行→测试报告生成) +7. 依次执行10个阶段(澄清→需求分析→设计→开发→自动部署→部署确认→测试验证→测试执行→测试报告生成→循环决策)🆕 8. 【Hook】需求文档确认后,调用 add_story MCP创建系统需求" ) ``` @@ -242,7 +256,7 @@ Task( 4. 输出识别结果和处理路径 5. 询问执行模式(快速/分步) 6. 创建任务工作区 -7. 依次执行7个阶段(澄清→需求分析→设计→开发→测试用例生成→测试执行→测试报告生成) +7. 依次执行10个阶段(澄清→需求分析→设计→开发→自动部署→部署确认→测试验证→测试执行→测试报告生成→循环决策) 8. 【Hook】需求文档确认后,调用 update_story MCP更新系统需求" ) ``` @@ -306,7 +320,7 @@ Task( 4. 输出识别结果和处理路径 5. 询问执行模式(快速/分步) 6. 创建任务工作区 -7. 依次执行7个阶段(澄清→需求分析→设计→开发→测试用例生成→测试执行→测试报告生成) +7. 依次执行10个阶段(澄清→需求分析→设计→开发→自动部署→部署确认→测试验证→测试执行→测试报告生成→循环决策) 8. 【Hook】需求文档确认后: - 先调用 update_business_story MCP更新业务需求 - 再调用 add_story MCP创建新的系统需求" @@ -646,9 +660,49 @@ SORT task_list BY 最后更新时间 DESC ## 第1阶段:需求分析与文档生成 📝 ## 第2阶段:设计方案生成 📐 ## 第3阶段:代码开发 💻 -## 第4阶段:测试用例生成 🧪 -## 第5阶段:测试执行 ⚡ -## 第6阶段:测试报告生成 📊 +## 第4阶段:自动部署 🚀 +## 第5阶段:部署确认 ⏸️ +## 第6阶段:测试验证 🧪 +## 第7阶段:测试执行 ⚡ +## 第8阶段:测试报告生成 📊 +## 第9阶段:循环决策 🔄 + +**决策逻辑**:根据测试报告决定下一步行动 + +### 决策条件 + +| 条件 | 操作 | 说明 | +|-----|------|------| +| ✅ 所有测试通过且无缺陷 | **退出循环** | 流程结束 | +| 🔄 存在失败测试用例或缺陷 | **继续循环** | 返回第1阶段,调用req-fix-bug-analyzer生成bug fix子需求 | +| ⚠️ 达到最大循环次数(10次) | **强制退出** | 停止循环,输出警告 | + +### 继续循环流程 + +当检测到失败测试用例或缺陷时: + +1. **读取测试报告**:从test-status.json获取失败信息 +2. **生成bug fix子需求**: + - 调用 `req-fix-bug-analyzer` Agent + - 生成类型为FIX的子需求文档 + - 在cycle-state.json中记录父子关系: + ```json + { + "parentRequirementId": "原需求ID", + "subRequirementType": "bug-fix", + "relatedTestCases": ["失败的测试用例ID列表"] + } + ``` +3. **子需求测试处理**: + - 测试用例生成:基于父需求测试用例文档**修改/新增**,不重新生成 + - 测试代码生成:基于父需求测试代码**修改/新增**,不重新生成 + - 测试执行:执行修改后的测试用例/代码 +4. **重复循环**:从第1阶段(需求分析)开始重新执行 + +### 状态文件 + +- **cycle-state.json**:记录循环次数、父子需求关系、失败用例列表 +- **test-status.json**:记录测试执行状态和结果 --- @@ -668,6 +722,11 @@ SORT task_list BY 最后更新时间 DESC 3. **中断恢复**:随时可以输入"暂停"中断,下次用 `resume` 继续 4. **多任务管理**:可以同时处理多个任务,每个任务有独立的工作目录 5. **模板适配**:支持自然语言描述,系统会自动提取信息并引导补全 +6. **DevOps 自动部署配置**🆕: + - 如需使用自动部署功能,需配置 CI/CD 系统识别 `#auto-deploy#` 标签 + - 配置文件:`.claude/config/deployment-config.json`(需修改 baseUrl 为实际远端地址) + - 自动部署流程:开发完成 → git-commit --auto-deploy → git-push --auto-deploy → CI/CD → 部署确认(用户手动) + - 参考文档:[Jenkins配置示例](#) / [GitLab CI配置示例](#) --- diff --git a/.claude/commands/git-commit.md b/.claude/commands/git-commit.md index 4055da372679d6e788960be465cd195885dd2420..d0af604f1b4e6336f6ad246a7ae5fb122a1e0e51 100644 --- a/.claude/commands/git-commit.md +++ b/.claude/commands/git-commit.md @@ -2,10 +2,14 @@ name: git-commit type: command description: Git提交命令,智能检测git变更并生成包含#AI commit#前缀的提交信息 -version: 3.3 +version: 3.4 author: DevSyncAgent Team -last_updated: 2026-01-23 +last_updated: 2026-02-02 changelog: + v3.4 - 2026-02-02 + - 🆕 新增 --auto-deploy 参数,支持触发CI/CD自动部署 + - 🔧 提交信息格式变为:#AI commit# #auto-deploy# {stage}阶段:{type} - {name} + - 🔧 新增自动部署触发说明和后续操作提示 v3.3 - 2026-01-23 - 添加推送提示,在提交成功后引导用户执行 /git-sync 推送代码 - 完善用户提示,提供两种推送方式(/git-sync推荐、git push手动) @@ -44,6 +48,15 @@ changelog: 只提交指定的文件(空格分隔的文件路径)。 +### 语法4:自动部署模式(新增)🆕 +``` +/git-commit --stage <阶段> --type <需求类型> --name <功能名称> --auto-deploy +``` + +提交代码并触发CI/CD自动部署到远端服务器。 + +**说明**:使用 `--auto-deploy` 参数后,提交信息将同时包含 `#AI commit#` 和 `#auto-deploy#` 两个标签,格式为:`#AI commit# #auto-deploy# {stage}阶段:{type} - {name}`。CI/CD系统检测到 `#auto-deploy#` 标签后自动执行部署流程。 + --- ## 参数说明 @@ -54,6 +67,7 @@ changelog: | `--type` | 需求类型代码 | NEW/ENHANCE/FIX/OPTIMIZE/REFACTOR/INTEGRATE | `--type NEW` | | `--name` | 功能名称 | 字符串 | `--name 用户注册` | | `--files` | 文件列表 | 空格分隔的文件路径 | `--files "file1.md file2.md"` | +| `--auto-deploy` | 触发自动部署 | 无(flag参数) | `--auto-deploy` | --- @@ -82,11 +96,14 @@ IF 命令包含 --stage AND --type AND --name THEN stage = 提取的 --stage 值 type_code = 提取的 --type 值 feature_name = 提取的 --name 值 + auto_deploy = 检查是否包含 --auto-deploy ELSE IF 命令包含 --files THEN mode = "指定文件模式" file_list = 提取的 --files 值 + auto_deploy = false ELSE mode = "自动检测模式" + auto_deploy = false END IF ``` @@ -128,7 +145,12 @@ type_mapping = { } type_cn = type_mapping.get(type_code, type_code) -commit_message = f"#AI commit# {stage}阶段:{type_cn} - {feature_name}" + +# 根据 --auto-deploy 参数决定提交信息格式 +if auto_deploy: + commit_message = f"#AI commit# #auto-deploy# {stage}阶段:{type_cn} - {feature_name}" +else: + commit_message = f"#AI commit# {stage}阶段:{type_cn} - {feature_name}" ``` #### 模式2:指定文件模式 @@ -293,6 +315,64 @@ git push --- +**成功时(带 --auto-deploy)🆕**: + +```markdown +## ✅ Git提交成功 + +**提交信息**:`#AI commit# #auto-deploy# {stage}阶段:{type_cn} - {feature_name}` + +**提交文件数**:{N}个 + +**提交SHA**:{commit_hash} + +--- + +## 📌 下一步操作 + +**代码已提交到本地仓库,需要推送到远程仓库以触发 CI/CD 部署**: + +### 方式1:自动推送(推荐)🆕 + +执行以下命令完成推送并触发 CI/CD: + +```bash +/git-push --auto-deploy +``` + +这将: +1. ✅ 检测待推送提交 +2. ✅ 自动推送到远程仓库(无需确认) +3. ✅ 触发 CI/CD 自动部署 + +### 方式2:使用 git-sync + +```bash +/git-sync +``` + +这将: +1. ✅ 检查并拉取远程更新 +2. ✅ 检测待推送提交 +3. ✅ 询问是否推送(需确认) +4. ✅ 推送到远程仓库 + +--- + +**推送完成后,CI/CD 将自动执行以下操作**: +1. 🔨 检测到 `#auto-deploy#` 标签 +2. 🔨 触发构建流水线 +3. 📦 部署到远端服务器 +4. ⏳ 预计部署时间:2-10分钟 + +--- + +💡 **部署进度监控**: +- 访问CI/CD控制台查看部署状态 +- 查看远端服务器日志确认部署进度 + +--- + ``` **失败时**: @@ -517,7 +597,7 @@ END IF ## 注意事项 -1. **前缀强制要求**:所有提交信息必须包含 `#AI commit#` 前缀 +1. **前缀强制要求**:所有提交信息必须包含 `#AI commit#` 前缀(包括auto-deploy模式,auto-deploy模式下的完整格式为:`#AI commit# #auto-deploy# {stage}阶段:{type} - {name}`) 2. **用户确认机制**:必须等待用户确认后才能执行git commit 3. **文件过滤**:自动忽略临时文件、构建产物 4. **错误处理**:git命令失败时提供清晰的错误信息和建议 diff --git a/.claude/commands/git-push.md b/.claude/commands/git-push.md new file mode 100644 index 0000000000000000000000000000000000000000..b2c65bab886b852eaa4dd9e1447691386353a810 --- /dev/null +++ b/.claude/commands/git-push.md @@ -0,0 +1,647 @@ +--- +name: git-push +type: command +description: Git推送命令,推送本地提交到远程仓库 +version: 1.0 +author: DevSyncAgent Team +last_updated: 2026-02-02 +changelog: + v1.0 - 2026-02-02 + - 初始版本发布 + - 支持检查本地待推送提交 + - 支持推送到远程仓库 + - 支持 --auto-deploy 模式(自动确认推送) + - 完整的错误处理(网络/认证/冲突三种场景) +--- + +# Git推送命令 + +你的任务是推送本地提交到远程仓库,确保代码同步到远程。 + +## 核心能力 + +| 能力 | 说明 | +|-----|------| +| **检查待推送提交** | 列出本地领先远程的提交 | +| **推送确认** | 普通模式需要用户确认,自动模式直接推送 | +| **错误处理** | 处理网络/认证/冲突三种错误场景 | +| **推送反馈** | 显示推送进度和结果 | + +## 📋 命令用法 + +### 语法1:普通推送(需要确认) +``` +/git-push +``` + +检查本地待推送提交,询问用户确认后推送。 + +### 语法2:自动推送模式(无需确认)🆕 +``` +/git-push --auto-deploy +``` + +自动推送到远程仓库,无需用户确认。用于 DevOps 自动部署场景。 + +### 语法3:指定远程仓库和分支 +``` +/git-push --remote --branch +``` + +推送到指定的远程仓库和分支。 + +--- + +## 执行流程 + +### Step 1: 检查Git仓库状态 + +```bash +git rev-parse --git-dir +``` + +**如果不在Git仓库中**: +```markdown +## ❌ 错误:非Git仓库 + +当前目录不是Git仓库。 + +**建议**: +- 确认是否在正确的项目目录中 +- 使用 `git init` 初始化仓库(如果需要) + +--- +``` + +--- + +### Step 2: 检查当前分支 + +```bash +git branch --show-current +``` + +**输出示例**: +```markdown +## 📤 Git推送 + +**当前分支**:master +``` + +--- + +### Step 3: 检查远程仓库配置 + +```bash +git remote -v +``` + +**如果未配置远程仓库**: +```markdown +## ⚠️ 未配置远程仓库 + +当前仓库没有配置远程origin。 + +**建议操作**: +```bash +git remote add origin <远程仓库URL> +``` + +**选项**: +1. 配置远程仓库后重新执行 +2. 取消推送 + +请选择 [1/2]: +``` + +--- + +### Step 4: 检查本地待推送提交 + +```bash +# 检查本地领先远程的提交 +git log @{u}..HEAD --oneline 2>&1 +``` + +**解析输出**: +- 统计领先提交数量 +- 提取提交SHA和提交信息 +- 识别提交类型 + +--- + +### Step 5: 判断推送模式 + +**根据是否包含 --auto-deploy 参数决定流程**: + +#### 模式A:普通推送(需要确认) + +**如果没有待推送提交**: +```markdown +## 📤 检查本地待推送提交 + +检测本地是否有领先远程的提交... + +**结果**:✅ 本地与远程同步,无需推送 + +💡 当前本地代码与远程仓库完全一致! + +--- + +## 🎉 无需推送 + +**推送状态**:✅ 本地与远程完全同步 + +💡 没有需要推送的提交。 +``` + +**如果有待推送提交**: +```markdown +## 📤 检查本地待推送提交 + +检测本地是否有领先远程的提交... + +**结果**:本地有 {N} 个待推送提交 + +**待推送提交列表**: +- abc1234 - {commit_message_1} +- def5678 - {commit_message_2} +- ghi9012 - {commit_message_3} + +**目标仓库**:origin/{branch} + +--- + +### 确认推送 + +是否推送上述 {N} 个提交到远程仓库?[Y/n] + +**选项**: +- **Y**:确认推送,将执行 `git push origin {branch}` +- **n**:取消推送 + +--- + +请输入 [Y/n]: +``` + +#### 模式B:自动推送(--auto-deploy)🆕 + +**检查到 --auto-deploy 参数,进入自动推送模式**: + +```markdown +## 📤 检查本地待推送提交 + +检测本地是否有领先远程的提交... + +**结果**:本地有 {N} 个待推送提交 + +**待推送提交列表**: +- abc1234 - #AI commit# #auto-deploy# 开发阶段:新增功能 - 用户注册 +- def5678 - 其他提交 + +**目标仓库**:origin/{branch} + +--- + +## 🚀 自动推送模式 + +**检测到 --auto-deploy 参数**,将自动推送上述 {N} 个提交到远程仓库。 + +**正在推送**... +``` + +--- + +### Step 6: 执行Git Push + +```bash +# 推送到远程仓库 +git push origin {branch} + +# 验证推送结果 +git log -1 --oneline +``` + +--- + +### Step 7: 输出推送结果 + +#### 成功时(普通模式) + +```markdown +## ✅ 推送成功 + +**推送提交数**:{N}个 +**目标仓库**:origin/{branch} +**最新提交**:{commit_hash} - {commit_message} + +--- + +## 🎉 推送完成 + +**推送状态**:✅ 本地与远程完全同步 + +💡 代码已成功推送到远程仓库! +``` + +#### 成功时(自动部署模式)🆕 + +```markdown +## ✅ 推送成功 + +**推送提交数**:{N}个 +**目标仓库**:origin/{branch} +**最新提交**:{commit_hash} - {commit_message} + +--- + +## 🚀 CI/CD 自动部署已触发 + +**提交信息**包含 `#auto-deploy#` 标签,CI/CD 系统检测到此标签后将自动执行部署流程: + +1. ✅ 检测到 `#auto-deploy#` 标签 +2. 🔨 触发构建流水线 +3. 📦 自动部署到远端服务器 +4. ⏳ 预计部署时间:2-10分钟 + +--- + +💡 **部署进度监控**: +- 访问CI/CD控制台查看部署状态 +- 查看远端服务器日志确认部署进度 +``` + +#### 失败时 + +##### 场景1:网络错误 + +```markdown +## ⚠️ 推送失败:网络错误 + +**错误信息**:{error_message} + +**可能原因**: +- 网络连接问题 +- 远程仓库不可访问 +- 认证失败 + +**建议操作**: +1. 检查网络连接 +2. 检查远程仓库URL:`git remote -v` +3. 检查认证配置(SSH密钥或凭据) +4. 稍后重新运行 `/git-push` + +--- + +**推送状态**:❌ 推送失败 + +💡 请解决上述问题后重新推送。 +``` + +##### 场景2:推送冲突(远程有新提交) + +```markdown +## ⚠️ 推送失败:远程有新更新 + +**错误原因**:推送时检测到远程仓库有新的提交(可能有他人刚推送) + +**当前状态**: +- 本地最新提交:{local_commit} +- 远程最新提交:{remote_commit} + +**建议操作**: +1. 先同步远程更新: + ```bash + /git-sync + ``` +2. 或手动执行: + ```bash + git pull --rebase origin {branch} + /git-push --auto-deploy + ``` + +--- + +**推送状态**:❌ 推送失败 + +💡 远程仓库刚有更新,请先同步后再推送。 +``` + +##### 场景3:认证失败 + +```markdown +## ⚠️ 推送失败:认证失败 + +**错误信息**:{error_message} + +**可能原因**: +- SSH密钥未配置或已过期 +- 凭据(用户名/密码/token)无效 +- 无推送权限 + +**建议操作**: +1. 检查认证配置: + - HTTPS方式:配置Git凭据管理器 + - SSH方式:检查SSH密钥并添加到远程仓库 +2. 验证权限:确认您有该仓库的推送权限 +3. 测试连接:`git push -v origin {branch}` 查看详细日志 + +--- + +**推送状态**:❌ 推送失败 + +💡 请解决认证问题后重新推送。 +``` + +--- + +## 参数说明 + +| 参数 | 说明 | 可选值 | 示例 | +|-----|------|--------|------| +| `--auto-deploy` | 自动推送模式(无需确认) | 无(flag参数) | `--auto-deploy` | +| `--remote` | 指定远程仓库名称 | 字符串 | `--remote origin` | +| `--branch` | 指定推送分支 | 字符串 | `--branch master` | + +--- + +## 使用示例 + +### 示例1:普通推送 + +```bash +/git-push +``` + +**输出**: +```markdown +## 📤 检查本地待推送提交 + +检测本地是否有领先远程的提交... + +**结果**:本地有 2 个待推送提交 + +**待推送提交列表**: +- abc1234 - #AI commit# 开发阶段:新增功能 - 用户注册 +- def5678 - 修复登录bug + +**目标仓库**:origin/master + +--- + +### 确认推送 + +是否推送上述 2 个提交到远程仓库?[Y/n] +``` + +### 示例2:自动部署推送 🆕 + +```bash +/git-push --auto-deploy +``` + +**输出**: +```markdown +## 📤 检查本地待推送提交 + +**结果**:本地有 1 个待推送提交 + +**待推送提交列表**: +- abc1234 - #AI commit# #auto-deploy# 开发阶段:新增功能 - 用户注册 + +**目标仓库**:origin/master + +--- + +## 🚀 自动推送模式 + +**检测到 --auto-deploy 参数**,将自动推送上述 1 个提交到远程仓库。 + +**正在推送**... + +## ✅ 推送成功 + +--- + +## 🚀 CI/CD 自动部署已触发 + +**提交信息**包含 `#auto-deploy#` 标签,CI/CD 系统检测到此标签后将自动执行部署流程... + +--- + +## 📌 下一步操作 + +**等待部署完成后,执行健康检查确认服务状态**: + +```bash +/health-check +``` +``` + +### 示例3:推送失败(远程有新更新) + +```bash +/git-push --auto-deploy +``` + +**输出**: +```markdown +## ⚠️ 推送失败:远程有新更新 + +**错误原因**:推送时检测到远程仓库有新的提交 + +**建议操作**: +1. 先同步远程更新: + ```bash + /git-sync + ``` +2. 或手动执行: + ```bash + git pull --rebase origin master + /git-push --auto-deploy + ``` +``` + +--- + +## 完整输出示例 + +### 示例1:普通推送成功 + +```markdown +## 📤 Git推送 + +**当前分支**:master + +--- + +## 📤 检查本地待推送提交 + +检测本地是否有领先远程的提交... + +**结果**:本地有 2 个待推送提交 + +**待推送提交列表**: +- abc1234 - #AI commit# 开发阶段:新增功能 - 用户注册 +- def5678 - #AI commit# 需求阶段:新增功能 - 用户导出 + +**目标仓库**:origin/master + +--- + +### 确认推送 + +是否推送上述 2 个提交到远程仓库?[Y/n] + +> 用户输入:Y + +**正在推送**... + +--- + +## ✅ 推送成功 + +**推送提交数**:2个 +**目标仓库**:origin/master +**最新提交**:def5678 + +--- + +## 🎉 推送完成 + +**推送状态**:✅ 本地与远程完全同步 + +💡 代码已成功推送到远程仓库! +``` + +### 示例2:自动部署推送成功 🆕 + +```markdown +## 📤 Git推送 + +**当前分支**:master + +--- + +## 📤 检查本地待推送提交 + +检测本地是否有领先远程的提交... + +**结果**:本地有 1 个待推送提交 + +**待推送提交列表**: +- abc1234 - #AI commit# #auto-deploy# 开发阶段:新增功能 - 用户注册 + +**目标仓库**:origin/master + +--- + +## 🚀 自动推送模式 + +**检测到 --auto-deploy 参数**,将自动推送上述 1 个提交到远程仓库。 + +**正在推送**... + +--- + +## ✅ 推送成功 + +**推送提交数**:1个 +**目标仓库**:origin/master +**最新提交**:abc1234 + +--- + +## 🚀 CI/CD 自动部署已触发 + +**提交信息**包含 `#auto-deploy#` 标签,CI/CD 系统检测到此标签后将自动执行部署流程: + +1. ✅ 检测到 `#auto-deploy#` 标签 +2. 🔨 触发构建流水线 +3. 📦 自动部署到远端服务器 +4. ⏳ 预计部署时间:2-10分钟 + +--- + +💡 **部署进度监控**: +- 访问CI/CD控制台查看部署状态 +- 查看远端服务器日志确认部署进度 +``` + +--- + +## 注意事项 + +1. **职责单一**:仅负责推送,不包含 commit 操作 +2. **普通模式需确认**:默认需要用户确认后才推送 +3. **自动模式**:`--auto-deploy` 时跳过确认,直接推送 +4. **错误处理**:对各种错误情况提供具体的解决建议 +5. **与 git-commit 配合**:先 `git-commit` 提交,再 `git-push` 推送 + +--- + +## 与其他命令的配合 + +### 推荐工作流 + +```bash +# 1. 提交代码 +/git-commit --stage 开发 --type NEW --name 用户注册 + +# 2. 推送代码 +/git-push + +# 或者使用 git-sync 一步完成 +/git-sync +``` + +### DevOps 自动部署流程 🆕 + +```bash +# 1. 完成开发后,提交代码 +/git-commit --stage 开发 --type NEW --name 用户注册 --auto-deploy + +# 2. 自动推送到远程(触发 CI/CD) +/git-push --auto-deploy + +# 3. 等待部署完成,执行健康检查 +/health-check + +# 4. 健康检查通过,执行测试 +/automated-test-executor +``` + +### 自动部署阶段调用 🆕 + +在 `dev-flow` 或 `req-type-classifier` 的自动部署阶段中: + +```python +# Step 1: 提交代码 +call_command("/git-commit --stage 开发 --type NEW --name 用户注册 --auto-deploy") + +# Step 2: 推送代码 +call_command("/git-push --auto-deploy") + +# Step 3: 执行健康检查 +call_command("/health-check") +``` + +--- + +## 版本信息 + +**版本**:1.0 +**作者**:DevSyncAgent Team +**创建日期**:2026-02-02 + +--- + +## 相关命令 + +- **git-commit**:提交本地变更 +- **git-sync**:双向同步(pull + push) + +--- + +**提示**:与 `git-commit --auto-deploy` 配合使用可触发完整的 DevOps 自动部署流程! diff --git a/.claude/config/agent-skill-sync-rules.json b/.claude/config/agent-skill-sync-rules.json new file mode 100644 index 0000000000000000000000000000000000000000..d67cf1437a9ece769a055b2aba19c0ddfb42ed03 --- /dev/null +++ b/.claude/config/agent-skill-sync-rules.json @@ -0,0 +1,126 @@ +{ + "schema_version": "1.0", + "description": "Agent与Skill双向同步规约配置", + "last_updated": "2026-01-26", + "pairs": [ + { + "pair_id": "functional-test-generator", + "agent_path": ".claude/agents/testing/functional-test-generator.md", + "skill_path": ".claude/skills/functional-test-generator/SKILL.md", + "sync_strategy": "bidirectional", + "version_sync": { + "enabled": true, + "strategy": "max_version", + "description": "两者版本号应保持一致,任一升级时同步升级另一个" + }, + "section_mapping": { + "核心流程步骤": { + "agent_section": "## 测试用例生成流程", + "skill_section": "## 测试用例生成流程", + "sync_mode": "full" + }, + "测试用例格式": { + "agent_section": "## 测试用例格式", + "skill_section": "## 测试用例格式", + "sync_mode": "full" + }, + "Feature转换逻辑": { + "agent_section": "## Feature文件转换逻辑", + "skill_section": "## Feature文件转换逻辑", + "sync_mode": "full" + }, + "质量标准": { + "agent_section": "## 质量标准", + "skill_section": "## 质量标准", + "sync_mode": "full" + }, + "代码示例": { + "agent_section": "## 自动化测试代码生成", + "skill_section": "## 自动化测试代码生成", + "sync_mode": "reference" + } + }, + "sync_rules": [ + { + "rule_id": "SYNC_001", + "name": "版本号同步规则", + "priority": "P0", + "description": "修改任一文件版本号时,必须同步升级另一个文件的版本号", + "check_pattern": "version:\\s*([0-9.]+)", + "action": "同步修改" + }, + { + "rule_id": "SYNC_002", + "name": "核心流程同步规则", + "priority": "P0", + "description": "核心生成流程步骤(第0步-第2步)必须保持一致", + "sections": ["第0步", "第0.2步", "第0.5步", "第1步", "第2步"], + "action": "双向同步" + }, + { + "rule_id": "SYNC_003", + "name": "新功能同步规则", + "priority": "P0", + "description": "Skill新增的功能(如代码分析、Wemind导入)需要同步到Agent", + "new_features": [ + "第0.3步:代码变更分析", + "第0.4步:接口定义解析", + "第0.6步:需求属性识别", + "第1.5步:静态代码分析", + "第2.5步:Wemind导入文件生成", + "单元测试用例格式", + "接口测试用例格式" + ], + "action": "Skill → Agent 同步" + }, + { + "rule_id": "SYNC_004", + "name": "changelog同步规则", + "priority": "P1", + "description": "changelog应包含本次同步的说明", + "changelog_format": "v{version} - {date}\n - 与[Agent|Skill]同步到{version}版本\n - 同步内容:{description}", + "action": "双方都记录" + }, + { + "rule_id": "SYNC_005", + "name": "示例代码同步规则", + "priority": "P2", + "description": "代码示例应保持一致(命名规范、结构)", + "action": "参考同步" + } + ], + "current_state": { + "agent_version": "3.2", + "skill_version": "3.3", + "sync_status": "outdated", + "sync_gap": "Skill领先Agent,需要将v3.3的新功能同步到Agent" + }, + "sync_checklist": [ + "检查version字段是否一致", + "检查核心流程步骤是否一致", + "检查测试用例格式是否一致", + "检查质量标准是否一致", + "检查新增功能是否已同步", + "更新changelog记录同步信息", + "验证changelog日期一致性" + ] + } + ], + "global_rules": { + "modification_workflow": [ + "1. 修改任一文件(Agent或Skill)", + "2. 检查.agent-skill-sync-rules.json获取同步配置", + "3. 识别变更的section和影响范围", + "4. 根据section_mapping确定需要同步的内容", + "5. 将变更应用到另一个文件", + "6. 同步升级版本号(如果需要)", + "7. 更新双方的changelog", + "8. 运行同步验证检查" + ], + "validation": { + "version_match": "两者版本号应一致", + "changelog_consistency": "changelog应记录同步信息", + "section_completeness": "映射的section应存在且内容一致" + } + } +} diff --git a/.claude/config/database-mcp-usage-rules.json b/.claude/config/database-mcp-usage-rules.json new file mode 100644 index 0000000000000000000000000000000000000000..6f18a1cec5082e1c860d4bea0aabc15d5a284bd0 --- /dev/null +++ b/.claude/config/database-mcp-usage-rules.json @@ -0,0 +1,137 @@ +{ + "ruleName": "数据库MCP使用规范", + "version": "1.0.0", + "priority": "HIGH", + "description": "定义在什么场景下必须优先使用数据库MCP而非查看代码/文档", + "mcpTool": "mcp__db-service__mysql_query", + + "decisionTree": { + "rootQuestion": "问题是否涉及数据库的运行时状态或当前数据?", + "yes": "使用数据库MCP查询", + "no": { + "followUpQuestion": "问题是否涉及历史变更或迁移过程?", + "yes": "查看Git记录、SQL迁移脚本", + "no": "查看代码/文档" + } + }, + + "scenarios": { + "mustUseMcp": [ + { + "scenario": "查询数据库当前状态", + "description": "需要获取数据库的实时状态信息", + "examples": [ + "系统有多少张表", + "某个表有多少行数据", + "某个字段的值分布", + "数据库当前的配置值" + ], + "action": "直接使用MCP查询,不要看SQL文件或代码" + }, + { + "scenario": "需求分析阶段了解数据模型", + "description": "在新增或修改需求时,需要了解现有数据库结构", + "examples": [ + "新增功能需要知道有哪些表、表之间的关系", + "设计新表前查看现有表的命名规范、字段类型", + "检查是否已有类似表避免重复造轮子", + "理解历史表(HIS)的设计模式", + "了解审计日志表的设计模式" + ], + "action": "使用MCP查询表结构、字段、注释,而非查看DDL文件" + }, + { + "scenario": "验证SQL正确性", + "description": "在开发或代码审查时验证SQL语句", + "examples": [ + "SQL是否能正确执行", + "字段名、表名是否存在", + "查询结果是否符合预期" + ], + "action": "使用MCP执行SQL验证" + }, + { + "scenario": "数据问题定位与调试", + "description": "排查数据相关问题时需要查看实际数据", + "examples": [ + "用户报告数据不对,查看实际数据", + "查询任务状态、流程进度", + "检查配置表里的值是否正确", + "验证数据是否正确插入" + ], + "action": "使用MCP查询实际数据" + }, + { + "scenario": "代码审查影响范围评估", + "description": "评估代码变更对数据库的影响范围", + "examples": [ + "修改某个表,查看有哪些表在用", + "删除某个字段,检查是否有代码依赖" + ], + "action": "使用MCP查询表关联、数据分布" + }, + { + "scenario": "性能分析", + "description": "分析数据库性能相关问题时", + "examples": [ + "查看表的大小、行数", + "检查索引使用情况", + "分析慢查询" + ], + "action": "使用MCP查询表统计信息" + } + ], + + "mustNotUseMcp": [ + { + "scenario": "查看SQL迁移脚本内容", + "description": "需要了解数据库变更的历史过程", + "examples": [ + "某个版本增加了哪些表", + "字段变更的历史记录", + "数据库升级脚本内容" + ], + "action": "查看db/目录下的SQL文件" + }, + { + "scenario": "理解代码逻辑", + "description": "需要了解业务逻辑或代码实现", + "examples": [ + "某个功能是如何实现的", + "数据是如何处理的", + "业务流程是什么" + ], + "action": "查看Java代码、文档" + } + ] + }, + + "checklist": { + "beforeQuery": [ + "确认MCP服务可用(settings.local.json中已配置mcp__db-service__mysql_query)", + "确认SQL语句正确,避免误操作(只读查询)", + "复杂查询先在测试环境验证" + ], + "afterQuery": [ + "验证结果是否符合预期", + "如果结果异常,检查SQL语句或数据状态", + "必要时将发现记录到知识库" + ] + }, + + "commonQueries": { + "查询所有表": "SELECT table_name, table_comment FROM information_schema.tables WHERE table_schema = DATABASE() ORDER BY table_name", + "查询表结构": "SHOW CREATE TABLE {table_name}", + "查询表字段": "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = '{table_name}'", + "查询表行数": "SELECT COUNT(*) FROM {table_name}", + "搜索包含关键字的表": "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name LIKE '%{keyword}%'", + "查询表关联": "SELECT TABLE_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE table_schema = DATABASE() AND TABLE_NAME = '{table_name}'" + }, + + "notes": [ + "数据库MCP是只读的,不会修改数据", + "优先使用MCP获取实时数据,代码/文档可能过时", + "复杂查询建议分步执行,逐步验证结果", + "发现数据异常时,及时与用户确认" + ] +} diff --git a/.claude/config/deployment-config.json b/.claude/config/deployment-config.json new file mode 100644 index 0000000000000000000000000000000000000000..238399f1e6189c1c111d13b2542493a24c7db613 --- /dev/null +++ b/.claude/config/deployment-config.json @@ -0,0 +1,29 @@ +{ + "version": "1.1", + "lastUpdated": "2026-02-08", + "description": "远端部署和测试配置(已移除健康检查配置)", + + "remoteServer": { + "baseUrl": "http://localhost:8080", + "apiBasePath": "/basePath", + "timeout": 30, + "enabled": true + }, + + "deployment": { + "autoDeployEnabled": true, + "waitTimeout": 600, + "maxCycles": 5 + }, + + "testing": { + "includeRemoteTests": true, + "remoteTestTimeout": 30, + "generateCurlCommands": true + }, + + "cicd": { + "webhookUrl": "", + "notificationEnabled": false + } +} diff --git a/.claude/config/stage-flow-rules.json b/.claude/config/stage-flow-rules.json index a0dd0a144c92c6ecb91a464c7c79b41b4b44cf46..fc9e0cc17683fe94106bc10f7ff11bd7b7d49c7e 100644 --- a/.claude/config/stage-flow-rules.json +++ b/.claude/config/stage-flow-rules.json @@ -1,8 +1,55 @@ { - "version": "1.3", - "lastUpdated": "2026-01-29", - "description": "阶段流转规则 - Phase 1仅实现明确需求工作流", + "version": "2.0", + "lastUpdated": "2026-02-08", + "description": "阶段流转规则 - 支持DevOps自动循环,循环时返回requirement阶段生成bug fix子需求", "changelog": { + "v2.0 - 2026-02-08": [ + "🐛 修复auto-deploy阶段未编译验证直接部署的严重问题", + "🆕 auto-deploy阶段新增编译验证步骤(build-verify)", + "🔧 支持多语言编译验证(Maven/Gradle/Python/Go/Node)", + "🔧 编译失败时中止部署流程,提示用户修复错误", + "✅ 确保只有编译通过的代码才会被commit和push" + ], + "v1.9 - 2026-02-08": [ + "🐛 修复auto-deploy阶段git-commit命令参数问题", + "🔧 移除未替换的模板变量{type}和{name}", + "🔧 使用git-commit自动检测模式,智能推断需求类型和功能名", + "✅ 修复commit信息缺失#auto-deploy#标签的问题" + ], + "v1.8 - 2026-02-08": [ + "🔄 循环决策返回点调整:从development改为requirement阶段", + "🔄 循环时调用req-fix-bug-analyzer生成bug fix子需求", + "🆕 子需求模式:测试阶段基于父需求测试用例修改/新增", + "🆕 cycle-state.json新增parentRequirementId字段记录父子关系", + "🔧 loopStages包含requirement阶段,支持完整bug修复循环" + ], + "v1.7 - 2026-02-05": [ + "🔧 移除health-check阶段,改为deployment-confirm阶段(用户手动确认部署完成)", + "🔧 移除开发阶段的健康检查接口自动生成功能" + ], + "v1.6 - 2026-02-02": [ + "🔧 testing-execution阶段skills支持参数化配置", + "🔧 automated-test-executor支持generate-only和execute-only模式", + "🔧 调整执行顺序:生成代码→审查代码→执行测试" + ], + "v1.5 - 2026-02-02": [ + "🆕 testing阶段新增test-case-document-reviewer Skill", + "🆕 testing-execution阶段新增test-code-reviewer Skill", + "🆕 新增测试用例文档审查报告交付物", + "🆕 新增测试代码审查报告交付物", + "🔧 testing阶段质量门禁更新:测试用例审查通过", + "🔧 testing-execution阶段质量门禁更新:测试代码审查通过" + ], + "v1.4 - 2026-02-02": [ + "🆕 DevOps自动循环支持", + "🆕 新增auto-deploy阶段:通过git-commit --auto-deploy触发CI/CD", + "🆕 新增deployment-confirm阶段:用户手动确认部署完成", + "🆕 新增cycle-decision阶段:根据测试报告决策是否继续循环", + "🆕 development阶段支持--auto-deploy参数", + "🆕 test-report-generation阶段支持循环决策输出", + "🔧 支持从cycle-state.json读取失败测试用例", + "🔧 完整DevOps循环:需求→设计→开发→部署→确认→测试→报告→决策" + ], "v1.3 - 2026-01-29": [ "🆕 新增test-report-generation阶段", "🆕 集成test-report Skill", @@ -25,10 +72,35 @@ "v1.0 - 2025-xx-xx": ["初始版本"] }, + "devOpsLoop": { + "enabled": true, + "maxCycles": 10, + "decisionCriteria": { + "exit": { + "description": "所有测试通过,无缺陷发现", + "conditions": [ + "failedCases == 0", + "defectCount == 0" + ] + }, + "continue": { + "description": "存在失败测试用例或缺陷,返回requirement阶段调用req-fix-bug-analyzer生成bug fix子需求", + "conditions": [ + "failedCases > 0 OR defectCount > 0" + ], + "targetStage": "requirement", + "subRequirementType": "bug-fix", + "action": "call_req_fix_bug_analyzer" + } + }, + "stateFile": "dev/active/{task-name}/cycle-state.json", + "testStatusFile": "dev/active/{task-name}/test-status.json" + }, + "workflows": { "waterfall-fast-delivery": { - "displayName": "瀑布式快速交付流程", - "description": "适用于明确需求的线性开发流程", + "displayName": "瀑布式快速交付流程(支持DevOps循环)", + "description": "适用于明确需求的线性开发流程,支持DevOps自动循环", "applicableRequirementTypes": ["defined"], "stages": [ @@ -121,6 +193,17 @@ "agents": ["java-code-developer", "python-code-developer"], + "devOpsIntegration": { + "enabled": true, + "features": { + "autoDeploy": { + "enabled": true, + "command": "/git-commit --auto-deploy", + "description": "通过git-commit --auto-deploy触发CI/CD自动部署(自动检测需求类型和功能名)" + } + } + }, + "defectIntegration": { "enabled": true, "mcpTools": { @@ -161,20 +244,133 @@ ] }, - "nextStage": "testing", + "nextStage": "auto-deploy", "entryMessage": "开始开发实现阶段。请遵循编码规范,编写高质量代码和单元测试。", - "exitMessage": "开发实现完成。准备进入测试阶段。" + "exitMessage": "开发实现完成。准备进入自动部署阶段。" + }, + + { + "id": "auto-deploy", + "name": "自动部署", + "displayName": "【自动部署】🆕", + "description": "编译验证、git-commit提交代码、git-push推送到远程仓库触发CI/CD自动部署", + "duration": "5%", + + "skills": [], + "skipOnFirstRun": false, + + "parameters": { + "autoDeploy": true + }, + + "steps": [ + { + "order": 1, + "type": "build-verify", + "description": "编译验证:确保代码可以成功编译", + "commands": { + "maven": "mvn clean compile -DskipTests", + "gradle": "gradle clean compileJava --no-daemon", + "python": "python -m py_compile $(find . -name '*.py' -not -path '*/venv/*' -not -path '*/.venv/*')", + "go": "go build ./...", + "node": "npm run build" + }, + "failureAction": "stop", + "errorMessage": "编译失败,请修复编译错误后重试" + }, + { + "order": 2, + "skill": "git-commit", + "command": "/git-commit --auto-deploy", + "description": "提交代码到本地仓库(包含#auto-deploy#标签,自动检测类型和功能名)" + }, + { + "order": 3, + "skill": "git-push", + "command": "/git-push --auto-deploy", + "description": "推送代码到远程仓库,触发CI/CD自动部署" + } + ], + + "deliverables": [ + { + "name": "build-verify", + "description": "编译验证通过", + "required": true + }, + { + "name": "git-commit", + "description": "Git提交记录(包含#auto-deploy#标签)", + "required": true + }, + { + "name": "git-push", + "description": "代码推送到远程仓库", + "required": true + } + ], + + "qualityGate": { + "name": "代码已编译并推送", + "criteria": [ + "编译验证通过", + "Git commit成功", + "提交信息包含#auto-deploy#标签", + "代码已推送到远程仓库" + ] + }, + + "nextStage": "deployment-confirm", + + "entryMessage": "开始自动部署阶段。首先进行编译验证,然后通过git-commit提交代码,最后git-push推送到远程仓库触发CI/CD部署。", + "exitMessage": "代码已推送到远程仓库,CI/CD部署已触发。准备进入部署确认阶段。" + }, + + { + "id": "deployment-confirm", + "name": "部署确认", + "displayName": "【部署确认】⏸️", + "description": "等待用户手动确认部署已完成", + "duration": "0%", + + "skills": [], + "skipOnFirstRun": false, + + "deliverables": [], + + "qualityGate": { + "name": "用户确认部署完成", + "criteria": [ + "用户确认部署已完成", + "服务已就绪" + ] + }, + + "nextStage": "testing", + + "entryMessage": "代码已推送到远程仓库,CI/CD自动部署已触发。请确认部署状态。", + "exitMessage": "用户确认部署已完成。准备进入测试阶段。" }, { "id": "testing", "name": "测试验证", "displayName": "【测试验证】", - "description": "集成测试、性能测试、缺陷修复", + "description": "测试用例文档生成、完整性审查、集成测试、性能测试、缺陷修复", "duration": "15%", "agents": [], + "skills": [ + { + "name": "functional-test-generator", + "description": "生成测试用例文档(支持子需求模式)" + }, + { + "name": "test-case-document-reviewer", + "description": "审查测试用例文档完整性(支持子需求模式)" + } + ], "deliverables": [ { @@ -182,32 +378,67 @@ "path": "docs/{branch}/testing/{功能名}_测试用例.md", "template": ".claude/templates/testing/test-plan-template.md", "required": true + }, + { + "name": "test-case-review-report", + "description": "测试用例文档审查报告", + "path": "dev/active/{task-name}/test-case-review-report.md", + "required": true } ], "qualityGate": { - "name": "测试通过", + "name": "测试用例审查通过", "criteria": [ - "所有测试用例通过", - "无P0/P1级别缺陷", - "性能指标达标" + "测试用例文档已通过完整性审查", + "测试用例覆盖所有功能点", + "测试用例包含边界场景", + "测试用例包含异常场景" ] }, "nextStage": "testing-execution", - "entryMessage": "开始测试验证阶段。由专职测试团队负责,AI辅助测试用例生成和缺陷分析。", - "exitMessage": "测试验证完成。准备进入测试执行阶段。" + "entryMessage": "开始测试验证阶段。生成测试用例文档并进行完整性审查。", + "exitMessage": "测试用例文档生成和审查完成。准备进入测试执行阶段。" }, { "id": "testing-execution", "name": "测试执行", "displayName": "【测试执行】", - "description": "生成测试代码、执行测试、生成验证结果", + "description": "生成测试代码(首次)、执行测试、代码审查、生成验证结果、远程curl测试", "duration": "10%", - "skills": ["automated-test-executor"], + "skills": [ + { + "name": "automated-test-executor", + "mode": "generate-only", + "description": "生成测试代码(不执行)" + }, + { + "name": "test-code-reviewer", + "description": "审查测试代码完整性" + }, + { + "name": "automated-test-executor", + "mode": "execute-only", + "description": "执行测试(不生成代码)" + } + ], + + "devOpsIntegration": { + "enabled": true, + "testStatusCheck": { + "enabled": true, + "file": "dev/active/{task-name}/test-status.json", + "skipIfGenerated": true + }, + "remoteCurlTest": { + "enabled": true, + "description": "生成远程curl测试脚本" + } + }, "deliverables": [ { @@ -215,6 +446,17 @@ "description": "可执行的测试代码", "required": true }, + { + "name": "test-code-review-report", + "description": "测试代码审查报告", + "path": "dev/active/{task-name}/test-code-review-report.md", + "required": true + }, + { + "name": "remote-curl-test", + "description": "远程curl测试脚本", + "required": true + }, { "name": "test-execution-report", "description": "自动化测试执行报告", @@ -226,6 +468,7 @@ "qualityGate": { "name": "测试执行完成", "criteria": [ + "测试代码已通过完整性审查", "测试代码已生成", "测试已执行", "生成测试执行报告" @@ -234,7 +477,7 @@ "nextStage": "test-report-generation", - "entryMessage": "开始测试执行阶段。我将生成测试代码、执行测试并生成验证结果。", + "entryMessage": "开始测试执行阶段。生成测试代码、进行完整性审查、执行测试并生成验证结果。", "exitMessage": "测试执行完成。准备进入测试报告生成阶段。" }, @@ -242,17 +485,43 @@ "id": "test-report-generation", "name": "测试报告生成", "displayName": "【测试报告生成】", - "description": "整合需求、测试用例、执行结果和缺陷信息,生成最终测试报告", + "description": "整合需求、测试用例、执行结果和缺陷信息,生成最终测试报告,并决策是否继续循环", "duration": "5%", "skills": ["test-report"], + "devOpsIntegration": { + "enabled": true, + "cycleDecision": { + "enabled": true, + "stateFile": "dev/active/{task-name}/cycle-state.json", + "decisionLogic": { + "exit": { + "conditions": ["failedCases == 0 AND defectCount == 0"], + "nextStage": null, + "message": "✅ DevOps 循环完成 - 所有测试通过" + }, + "continue": { + "conditions": ["failedCases > 0 OR defectCount > 0"], + "nextStage": "requirement", + "message": "🔄 DevOps 循环继续 - 返回requirement阶段调用req-fix-bug-analyzer生成bug fix子需求" + } + } + } + }, + "deliverables": [ { "name": "final-test-report", "description": "最终测试报告", "path": "docs/{branch}/testing/reports/{功能名}_最终测试报告.md", "required": true + }, + { + "name": "cycle-state", + "description": "循环状态文件", + "path": "dev/active/{task-name}/cycle-state.json", + "required": true } ], @@ -262,14 +531,40 @@ "测试报告已生成", "包含完整的测试统计", "包含缺陷分析", - "包含测试结论和建议" + "包含测试结论和建议", + "包含循环决策结果" ] }, - "nextStage": "ops", + "nextStage": "cycle-decision", - "entryMessage": "开始测试报告生成阶段。我将整合所有测试数据生成最终测试报告。", - "exitMessage": "🎉 测试报告生成完成!准备进入运维部署阶段。" + "entryMessage": "开始测试报告生成阶段。我将整合所有测试数据生成最终测试报告并进行循环决策。", + "exitMessage": "测试报告生成完成。准备进行循环决策。" + }, + + { + "id": "cycle-decision", + "name": "循环决策", + "displayName": "【循环决策】🆕", + "description": "根据测试报告决策是否继续DevOps循环修复bug", + "duration": "0%", + + "skills": [], + + "deliverables": [], + + "qualityGate": { + "name": "循环决策完成", + "criteria": [ + "已读取cycle-state.json", + "已根据测试结果做出决策" + ] + }, + + "nextStage": "dynamic", + + "entryMessage": "开始循环决策阶段。将根据测试结果决定下一步行动。", + "exitMessage": "循环决策完成。" }, { @@ -312,6 +607,20 @@ "automatic": false, "requireUserApproval": true, "allowSkipStage": false, - "allowRollback": true + "allowRollback": true, + "devOpsLoop": { + "enabled": true, + "maxCycles": 10, + "loopStages": ["requirement", "design", "development", "auto-deploy", "deployment-confirm", "testing", "testing-execution", "test-report-generation", "cycle-decision"], + "subRequirementMode": { + "enabled": true, + "parentRequirementField": "parentRequirementId", + "subRequirementTypeField": "subRequirementType", + "testInheritance": { + "enabled": true, + "description": "子需求测试基于父需求测试用例修改/新增,不重新生成" + } + } + } } } diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 44e2f786d482e057c67579d52a6f1daf301ccaa9..dd3b814b5243e6f43322d62aeb20773969d40e42 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -22,11 +22,20 @@ "WebSearch", "WebFetch(domain:www.alexanderlammers.net)", "WebFetch(domain:blog.cloudflare.com)", - "mcp__dpms__get_story_info_with_content" + "mcp__dpms__get_story_info_with_content", + "mcp__filesystem__edit_file", + "mcp__filesystem__write_file", + "mcp__filesystem__list_allowed_directories", + "Bash(findstr:*)", + "mcp__thinking__sequentialthinking", + "mcp__db-service__mysql_query" ] }, "enableAllProjectMcpServers": true, "enabledMcpjsonServers": [ - "tctptest-bug-service","dpms" + "tctptest-bug-service", + "dpms", + "db-service", + "sdp" ] } diff --git a/.claude/skills/automated-test-executor/SKILL.md b/.claude/skills/automated-test-executor/SKILL.md index c50dfc84fcf4c97e771a3cc4518acea923ae0d9a..30686f75a2bd2d7104dcfba226952d95e55c4f0b 100644 --- a/.claude/skills/automated-test-executor/SKILL.md +++ b/.claude/skills/automated-test-executor/SKILL.md @@ -2,10 +2,77 @@ name: automated-test-executor type: testing description: 基于Cucumber BDD的自动化测试代码生成、执行和报告生成专家 -version: 1.3 +version: 2.4 author: DevSyncAgent Team -last_updated: 2026-01-28 +last_updated: 2026-02-08 changelog: + v2.4 - 2026-02-08 + - 🔧 **重要改进**:测试执行逻辑优化,所有测试都会执行完毕 + - 🔧 单元测试失败不再阻断后续测试执行 + - 🔧 Cucumber测试失败不再阻断后续测试执行 + - ✅ 所有测试执行完毕后统一判断最终结果 + - ✅ 测试结果详细显示:通过/失败状态一目了然 + - ✅ 部分测试失败时给出清晰的汇总信息 + v2.3 - 2026-02-08 + - 🆕 第6步新增:执行远程API测试(remote-api-test.sh 或 remote_api_test.py) + - 🔧 测试执行顺序:单元测试 → Cucumber测试 → 性能测试 → 远程API测试 + - ✅ 远程API测试结果包含在测试汇总中 + - ✅ 未找到远程API测试脚本时给出提示和建议 + v2.2 - 2026-02-08 + - ❌ 移除测试执行时的健康检查步骤(第4.9步) + - 🔧 从remote-api-test.sh脚本模板中移除健康检查代码 + - 🔧 从Python测试脚本模板中移除健康检查代码 + - ✅ 测试直接执行,不再等待服务健康检查 + - ✅ 简化配置:不再需要healthCheckPath配置 + v2.1 - 2026-02-08 + - 🐛 修复remote-api-test.sh脚本使用localhost而非配置文件中真实地址的问题 + - 🔴 P0级强制要求:生成脚本时必须使用deployment-config.json中的实际配置值 + - 🔧 新增配置值替换流程:读取配置 → 生成脚本时将实际值写入(heredoc方式) + - ✅ 确保生成的BASE_URL、API_BASE_PATH使用真实远端地址 + - ❌ 禁止在脚本中使用硬编码的localhost值 + v2.0 - 2026-02-08 + - 🔴 **强制要求:Cucumber测试代码必须基于JUnit 5,不再使用JUnit 4** + - 🔧 移除cucumber-junit依赖(JUnit 4),替换为cucumber-junit-platform-engine(JUnit 5) + - 🔧 新增junit-platform-suite依赖,支持JUnit 5的@Suite注解 + - 🔧 Cucumber Runner类更新为JUnit 5格式:@Suite + @SelectClasspathResource + @Cucumber + - ❌ 移除JUnit 4的@RunWith(Cucumber.class)注解 + - ✅ 确保所有生成的测试代码使用JUnit 5(org.junit.jupiter.api.*) + v1.9 - 2026-02-08 + - 🐛 修复Cucumber依赖缺失时仍继续生成测试代码的问题 + - 🔴 P0级强制执行:检测到依赖缺失时必须先添加依赖 + - 🆕 新增强制依赖检测机制:不添加依赖不得继续后续步骤 + - ✅ 确保生成的测试代码能够正常编译和执行 + v1.8 - 2026-02-08 + - 🆕 新增子需求模式检测与处理 + - 🔄 支持DevOps自动循环中子需求测试执行 + - 🔄 子需求模式:基于父需求测试代码执行修改的测试 + - 🔄 从cycle-state.json读取parentRequirementId + - 🔄 仅执行@Tag("sub-requirement")标记的测试方法 + - 🔄 测试报告基于修改内容生成 + v1.7 - 2026-02-02 + - 🆕 支持分阶段执行模式:generate-only(仅生成)、execute-only(仅执行) + - 🔧 优化与test-code-reviewer的集成:先生成代码→审查→再执行 + v1.6 - 2026-02-02 + - 🆕 DevOps自动循环支持:新增测试状态跟踪机制 + - 🆕 新增Step -1:检查test-status.json,避免循环中重复生成测试 + - 🆕 新增Step 4.8:生成远程curl测试用例,支持远端服务测试 + - 🆕 新增Step 4.9:集成health-check,部署后自动执行健康检查 + - 🆕 支持读取deployment-config.json获取远端服务配置 + - 🆕 支持循环模式:首次生成测试代码,后续循环仅执行测试 + v1.5 - 2026-02-02 + - 🆕 新增第4.8步:JMeter未安装时的备选性能测试脚本生成 + - 🆕 新增Shell/curl脚本模板:使用系统自带curl进行HTTP并发性能测试 + - 🆕 新增Python/requests脚本模板:使用requests库进行HTTP并发性能测试 + - 🆕 增强第6步:测试执行脚本支持备选脚本的检测和执行 + - 🔧 JMeter未安装时自动降级到备选脚本,确保性能测试不被跳过 + v1.4 - 2026-02-02 + - 🆕 新增第0.5步:性能测试需求检测(自动检测Feature文件、测试用例文档、需求文档) + - 🆕 增强性能测试生成策略:支持多场景(HTTP接口/算法方法/数据库/默认轻量级) + - 🆕 新增算法/方法性能测试模板(JUnit @Test + @Tag("performance")) + - 🆕 新增数据库性能测试模板(JDBC性能测试) + - 🆕 新增默认轻量级性能测试模板(简单时间测量) + - 🔧 修改性能测试执行脚本:强制执行,增强检测逻辑(JUnit优先,JMeter/Locust备选) + - 🔧 性能测试结果必须包含在验证结果报告中 v1.3 - 2026-01-28 - 🔴 P0修复: 移除 -DfailIfNoTests=false 参数,防止无测试时返回假阳性成功 - 🔴 P0修复: 添加编译前置检查(mvn clean compile),确保项目可编译后再执行测试 @@ -49,6 +116,67 @@ changelog: | **测试执行** | 自动执行所有类型测试 | | **结果生成** | 生成自动化测试验证结果 | +## 执行模式 🆕 + +本Skill支持三种执行模式,通过`mode`参数控制: + +| 模式 | 说明 | 使用场景 | +|-----|------|----------| +| **默认** | 完整模式:生成代码 + 执行测试 | 单独调用时 | +| **generate-only** | 仅生成测试代码,不执行 | 与test-code-reviewer集成时首次调用 | +| **execute-only** | 仅执行测试,不生成代码 | 与test-code-reviewer集成时二次调用 | + +### 模式检测逻辑 + +```bash +# 从stage-flow-rules.json读取mode参数 +MODE=$(jq -r '.mode // "default"' $STAGE_CONFIG) + +if [ "$MODE" = "generate-only" ]; then + # 仅执行:Step -1 → Step 5(生成代码) + # 跳过:Step 6(执行测试) + echo "⚙️ 执行模式:generate-only(仅生成测试代码)" +elif [ "$MODE" = "execute-only" ]; then + # 跳过:Step -1 → Step 5(生成代码) + # 仅执行:Step 6(执行测试) + echo "⚙️ 执行模式:execute-only(仅执行测试)" +else + # 默认模式:执行所有步骤 + echo "⚙️ 执行模式:default(生成代码 + 执行测试)" +fi +``` + +### DevOps循环中的执行顺序 + +```mermaid +graph LR + A[automated-test-executor
generate-only] --> B[test-code-reviewer] --> C[automated-test-executor
execute-only] + + style A fill:#e1f5ff + style B fill:#fff4e1 + style C fill:#e8f5e9 +``` + +1. **第一次调用**(generate-only): + - 检查test-status.json + - 生成Cucumber测试代码 + - 生成单元测试代码 + - 生成性能测试脚本 + - 生成远程curl测试脚本 + - **停止**,不执行测试 + +2. **test-code-reviewer 审查**: + - 检查测试代码完整性 + - 识别空实现、假阳性断言 + - 输出审查报告 + +3. **第二次调用**(execute-only): + - 跳过代码生成步骤 + - 执行所有测试 + - 生成验证结果 + +--- + ## 输入 **优先级顺序**: @@ -84,26 +212,170 @@ docs/{branch}/testing/ └── {功能名}_自动化测试验证结果.md # 验证结果 ``` +## 子需求模式检测 🆕v1.8 + +**目标**:检测当前是否为DevOps循环中子需求的测试执行 + +### 检测逻辑 + +```markdown +1. 检查 cycle-state.json 是否存在 + IF 存在 THEN + 读取 parentRequirementId 和 subRequirementType + + IF subRequirementType == "bug-fix" THEN + 进入【子需求执行模式】 + ELSE + 进入【标准执行模式】 + END IF +ELSE + 进入【标准执行模式】 +END IF +``` + +### 子需求执行模式处理策略 + +当检测到子需求模式时: + +**1. 读取父需求测试代码** +```markdown +路径:src/test/java/**/*.java 或 src/test/**/*.py +``` + +**2. 执行策略差异** + +| 执行维度 | 标准模式 | 子需求模式 | +|---------|---------|-----------| +| 代码生成 | 生成完整测试代码 | 基于父需求代码修改/新增 | +| 测试执行 | 执行所有测试 | 执行标记@Tag("sub-requirement")的测试 | +| 报告生成 | 完整测试报告 | 基于修改内容的报告 | + +**3. 测试执行调整** +```bash +# 子需求模式:仅执行标记为子需求的测试 +mvn test -Dgroups="sub-requirement" # Maven +pytest -m sub_requirement # pytest +``` + +**4. 输出调整** +- ✅ 报告中标识子需求模式 +- ✅ 说明基于父需求测试的修改执行 +- ✅ 提供修改后的测试结果 + +**5. 子需求模式提示** +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔄 **子需求执行模式**(DevOps自动循环) + +检测到当前为子需求测试执行: +- 父需求ID: {parentRequirementId} +- 执行策略: 仅执行@Tag("sub-requirement")标记的测试 + +📋 **执行重点**: +- ✅ 执行新增的测试方法 +- ✅ 执行修改的测试方法 +- ✅ 验证失败场景是否修复 + +> 📌 父需求测试代码:{父需求测试代码路径} +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + ## 测试生成流程 ```mermaid graph TD - A[开始] --> B[第0步: 环境检测与准备] - B --> C{项目语言?} - C -->|Java| D[检测Cucumber依赖] - C -->|Python| E[检测behave依赖] - D --> F{已安装?} - E --> F - F -->|否| G[引入Cucumber依赖] - F -->|是| H[第1步: 读取输入文件] - G --> H - H --> I[第2步: 生成Cucumber测试] - I --> J[第3步: 生成单元测试] - J --> K[第4步: 生成性能测试] - K --> L[第5步: 测试代码合并] - L --> M[第6步: 执行测试] - M --> N[第7步: 生成验证结果] - N --> O[结束] + A[开始] --> B[第-1步: 检查测试状态] + B --> C{测试已生成?} + C -->|是| D[跳到第6步: 执行测试] + C -->|否| E[第0步: 环境检测与准备] + E --> F{项目语言?} + F -->|Java| G[检测Cucumber依赖] + F -->|Python| H[检测behave依赖] + G --> I{已安装?} + H --> I + I -->|否| J[引入依赖] + I -->|是| K[第1步: 读取输入文件] + J --> K + K --> L[第2步: 生成Cucumber测试] + L --> M[第3步: 生成单元测试] + M --> N[第4步: 生成性能测试] + N --> O[第4.8步: 生成远程curl测试] + O --> Q[第5步: 测试代码合并] + Q --> R[第6步: 执行测试] + D --> R + R --> S[第7步: 生成验证结果] + S --> T[结束] +``` + +--- + +## 第-1步:检查测试状态 🆕 + +**目标**:检查测试是否已在之前生成,避免在 DevOps 循环中重复生成测试代码。 + +### 状态文件位置 + +```bash +STATUS_FILE="dev/active/{task-name}/test-status.json" +``` + +### 检查逻辑 + +```bash +# 检查测试状态文件是否存在 +if [ -f "$STATUS_FILE" ]; then + # 读取状态 + TEST_CASES_GENERATED=$(jq -r '.testCasesGenerated // false' $STATUS_FILE) + TEST_CODE_GENERATED=$(jq -r '.testCodeGenerated // false' $STATUS_FILE) + + if [ "$TEST_CASES_GENERATED" = "true" ] && [ "$TEST_CODE_GENERATED" = "true" ]; then + echo "========================================" + echo "✅ 测试代码已生成,跳过生成步骤" + echo "========================================" + echo "测试用例文档: 已生成 ✅" + echo "测试代码: 已生成 ✅" + echo "" + echo "💡 直接执行测试(第6步)..." + echo "" + # 跳转到第6步:执行测试 + goto_step_6 + fi +fi + +echo "========================================" +echo "📝 首次生成测试代码" +echo "========================================" +# 继续执行第0步 +``` + +### 状态文件格式 + +**test-status.json**: +```json +{ + "testCasesGenerated": true, + "testCodeGenerated": true, + "lastGenerated": "2026-02-02T10:30:00", + "cycleCount": 1 +} +``` + +### 更新状态文件 + +在完成测试代码生成后(第5步之后),更新状态文件: + +```bash +# 创建或更新状态文件 +cat > $STATUS_FILE << EOF +{ + "testCasesGenerated": true, + "testCodeGenerated": true, + "lastGenerated": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", + "cycleCount": $(jq -r '.cycleCount // 0' $STATUS_FILE 2>/dev/null || echo 0) +} +EOF ``` --- @@ -133,7 +405,9 @@ else fi ``` -### 0.2 Java项目 - 检测并引入Cucumber +### 0.2 Java项目 - 检测并引入Cucumber 🔴 P0级强制执行 + +**重要**:此步骤是P0级强制执行,**不得跳过**! **检测Cucumber依赖**: @@ -147,7 +421,36 @@ else fi ``` -**自动引入Cucumber依赖** (Maven): +**🚨 P0级强制执行规则**: + +当检测到Cucumber依赖不存在时,**必须**执行以下操作: + +1. **立即停止生成测试代码** +2. **自动添加Cucumber依赖到pom.xml** +3. **执行 `mvn dependency:resolve` 下载依赖** +4. **验证依赖成功添加后,才能继续第1步** + +```bash +# 🔴 P0级强制执行流程 +if ! grep -q "io.cucumber" pom.xml; then + echo "========================================" + echo "🔴 P0级强制步骤:添加Cucumber依赖" + echo "========================================" + echo "⚠️ Cucumber依赖不存在" + echo "📌 正在自动添加Cucumber依赖到pom.xml..." + + # 添加Cucumber依赖(使用sed或xmlstarlet) + # ...添加依赖的代码... + + echo "📌 正在下载依赖..." + mvn dependency:resolve + + echo "✅ Cucumber依赖已成功添加并下载" + echo "========================================" +fi +``` + +**自动引入Cucumber依赖** (Maven) 🔴 **仅使用 JUnit 5**: ```xml @@ -160,23 +463,23 @@ fi test - + io.cucumber - cucumber-junit + cucumber-junit-platform-engine 7.14.0 test - + - io.cucumber - cucumber-picocontainer - 7.14.0 + org.junit.platform + junit-platform-suite + 1.10.0 test - + org.junit.jupiter junit-jupiter @@ -184,6 +487,14 @@ fi test + + + io.cucumber + cucumber-picocontainer + 7.14.0 + test + + org.mockito @@ -202,20 +513,22 @@ fi ``` -**Gradle项目** (`build.gradle`): +**Gradle项目** (`build.gradle`) 🔴 **仅使用 JUnit 5**: ```groovy // 添加到dependencies dependencies { testImplementation 'io.cucumber:cucumber-java:7.14.0' - testImplementation 'io.cucumber:cucumber-junit:7.14.0' - testImplementation 'io.cucumber:cucumber-picocontainer:7.14.0' + // 🔴 使用cucumber-junit-platform-engine,不是cucumber-junit + testImplementation 'io.cucumber:cucumber-junit-platform-engine:7.14.0' + testImplementation 'org.junit.platform:junit-platform-suite:1.10.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0' + testImplementation 'io.cucumber:cucumber-picocontainer:7.14.0' testImplementation 'org.mockito:mockito-core:5.5.0' testImplementation 'org.assertj:assertj-core:3.24.2' } -// 配置测试任务 +// 配置测试任务 - 必须使用JUnit Platform test { useJUnitPlatform() } @@ -274,6 +587,142 @@ fi --- +## 第0.5步:性能测试需求检测 🆕 + +**目标**:检测项目是否需要性能测试,以及性能测试的类型 + +### 检测逻辑 + +**Step 1:从Feature文件检测性能标签** + +```bash +# 检查Feature文件中的@performance标签 +PERFORMANCE_NEEDED="" +PERFORMANCE_TYPE="" + +if grep -r "@performance" features/ 2>/dev/null; then + PERFORMANCE_NEEDED=true + PERFORMANCE_TYPE="feature" + echo "✅ 检测到性能测试需求(来源:Feature文件 @performance标签)" +fi + +# 统计检测到的性能标签 +PERFORMANCE_TAGS=$(grep -h "@performance" features/*.feature 2>/dev/null | sort -u) +if [ -n "$PERFORMANCE_TAGS" ]; then + echo "📌 检测到的性能标签:" + echo "$PERFORMANCE_TAGS" | while read -r tag; do + echo " - $tag" + done +fi +``` + +**Step 2:从测试用例文档检测性能测试** + +```bash +# 检查测试用例文档中是否包含性能测试章节 +if grep -r "性能测试\|performance" docs/*/testing/*测试用例.md 2>/dev/null; then + PERFORMANCE_NEEDED=true + PERFORMANCE_TYPE="test_case" + echo "✅ 检测到性能测试需求(来源:测试用例文档)" +fi +``` + +**Step 3:从需求文档检测性能要求** + +```bash +# 检查需求文档中的性能相关关键词 +if grep -ri "性能\|响应时间\|吞吐量\|并发\|延迟\|负载\|压力" docs/*/requirements/*_需求.md 2>/dev/null; then + PERFORMANCE_NEEDED=true + PERFORMANCE_TYPE="requirement" + echo "✅ 检测到性能测试需求(来源:需求文档)" +fi +``` + +**Step 4:默认策略** + +```bash +# 如果没有明确声明无需性能测试,则默认生成轻量级性能测试 +if [ -z "$PERFORMANCE_NEEDED" ]; then + # 检查是否有明确声明无需性能测试 + if grep -ri "无需性能测试\|不包含性能测试\|跳过性能测试" docs/ 2>/dev/null; then + PERFORMANCE_NEEDED=false + echo "⚠️ 需求明确声明无需性能测试" + else + # 默认生成轻量级性能测试 + PERFORMANCE_NEEDED=true + PERFORMANCE_TYPE="default" + echo "📌 未检测到明确的性能测试需求,将使用默认轻量级性能测试" + fi +fi +``` + +### 性能测试类型分类 + +**自动检测项目类型并选择性能测试方案**: + +| 项目类型 | 检测条件 | 性能测试方案 | 说明 | +|---------|---------|-------------|------| +| **HTTP接口** | `@RestController`、`@RequestMapping` | JMeter / Locust | HTTP接口压力测试 | +| **算法/方法** | `*Sort*.java`、`*Util*.java`、`*Algorithm*.java` | JUnit性能测试 | 方法执行时间测量 | +| **数据库操作** | `JPA`、`MyBatis`、`@Repository` | JDBC性能测试 | 数据库查询性能 | +| **默认轻量级** | 无特定类型 | 简单时间测量 | 基础性能验证 | + +**类型检测脚本**: + +```bash +PROJECT_TYPE="" + +# 检测HTTP接口项目 +if find src/main/java -name "*.java" -exec grep -l "@RestController\|@RequestMapping\|@GetMapping" {} \; 2>/dev/null | head -1; then + PROJECT_TYPE="http_api" + echo "📊 项目类型检测:HTTP接口项目" +fi + +# 检测算法/工具类 +if [ -z "$PROJECT_TYPE" ]; then + if find src/main/java -name "*Sort*.java" -o -name "*Util*.java" -o -name "*Algorithm*.java" 2>/dev/null | head -1; then + PROJECT_TYPE="algorithm" + echo "📊 项目类型检测:算法/工具类项目" + fi +fi + +# 检测数据库操作 +if [ -z "$PROJECT_TYPE" ]; then + if find src/main/java -name "*.java" -exec grep -l "JdbcTemplate\|JPA\|MyBatis\|@Repository\|@Entity" {} \; 2>/dev/null | head -1; then + PROJECT_TYPE="database" + echo "📊 项目类型检测:数据库操作项目" + fi +fi + +# 默认类型 +if [ -z "$PROJECT_TYPE" ]; then + PROJECT_TYPE="default" + echo "📊 项目类型检测:使用默认性能测试方案" +fi +``` + +### 性能测试需求输出 + +```markdown +## 性能测试需求检测结果 🆕 + +| 检测项 | 结果 | +|-------|-----| +| 是否需要性能测试 | ✅ 是 / ❌ 否 | +| 需求来源 | Feature文件 / 测试用例文档 / 需求文档 / 默认策略 | +| 项目类型 | HTTP接口 / 算法方法 / 数据库操作 / 默认 | +| 性能测试方案 | JMeter / Locust / JUnit性能测试 / 轻量级测试 | + +### 性能测试生成策略 + +根据检测结果,将生成以下性能测试: +- 测试类型:{检测到的类型} +- 生成方案:{对应的测试方案} +- 测试数量:{预计生成的测试用例数} +``` + +--- + ## 第1步:读取输入文件 ### 1.1 读取Feature文件 @@ -498,20 +947,24 @@ def then_result_should_be(context, expected): ### 2.2 生成Cucumber Runner类 -**Java Runner示例**: +**Java Runner示例(JUnit 5)🔴 必须使用此模板**: ```java package com.example.cucumber.runner; -import io.cucumber.junit.Cucumber; -import io.cucumber.junit.CucumberOptions; -import org.junit.runner.RunWith; - -@RunWith(Cucumber.class) -@CucumberOptions( - // Feature文件路径 - features = "classpath:features", - // Step Definitions路径 - glue = {"com.example.cucumber.steps"}, +import io.cucumber.junit.platform.engine.Cucumber; +import org.junit.platform.suite.api.IncludeClassNamePatterns; +import org.junit.platform.suite.api.SelectClasspathResource; +import org.junit.platform.suite.api.Suite; + +/** + * Cucumber Test Runner - JUnit 5 + * + * 🔴 重要:使用JUnit 5的@Suite注解,不是JUnit 4的@RunWith + */ +@Suite +@IncludeClassNamePatterns(".*Test") // 包含所有以Test结尾的类 +@SelectClasspathResource("features") // 指定Feature文件位置 +@Cucumber( // 插件配置 plugin = { "pretty", @@ -525,8 +978,8 @@ import org.junit.runner.RunWith; monochrome = true, strict = true ) -public class CucumberRunner { - // Runner类,无需添加代码 +public class CucumberRunnerTest { + // JUnit 5 Runner类,使用@Suite注解,无需添加代码 } ``` @@ -826,6 +1279,73 @@ class TestBubbleSort: ## 第4步:生成性能测试 +### 4.0 性能测试生成策略 🆕 + +**核心原则**:除非需求明确声明无需性能测试,否则必须生成性能测试代码。 + +#### 生成决策树 + +``` +检测性能测试需求(第0.5步) + │ + ├─ 需求来源:Feature文件 @performance标签? + │ └─ 提取性能要求(并发数、响应时间、吞吐量) + │ + ├─ 项目类型检测 + │ ├─ HTTP接口 → 生成JMeter/Locust脚本 + │ ├─ 算法/方法 → 生成JUnit性能测试方法 + │ ├─ 数据库操作 → 生成JDBC性能测试方法 + │ └─ 默认 → 生成轻量级性能测试 + │ + └─ 生成对应场景的性能测试代码 +``` + +#### 多场景性能测试方案 + +| 场景类型 | 检测条件 | 生成方案 | 工具/框架 | +|---------|---------|---------|----------| +| **HTTP接口** | `@RestController`、`@RequestMapping` | API压力测试 | JMeter / Locust | +| **算法/方法** | `*Sort*.java`、`*Util*.java`、`*Algorithm*.java` | 方法执行时间测量 | JUnit @Test | +| **数据库操作** | `JPA`、`MyBatis`、`@Repository` | 查询性能测试 | JUnit + JDBC | +| **默认轻量级** | 无特定类型 | 基础时间验证 | System.currentTimeMillis() | + +#### 生成条件检查 + +```bash +# 条件1:检查是否有HTTP接口 +HAS_HTTP_API=false +if find src/main/java -name "*.java" -exec grep -l "@RestController\|@RequestMapping\|@GetMapping" {} \; 2>/dev/null | head -1; then + HAS_HTTP_API=true +fi + +# 条件2:检查是否有算法/工具类 +HAS_ALGORITHM=false +if find src/main/java -name "*Sort*.java" -o -name "*Util*.java" -o -name "*Algorithm*.java" 2>/dev/null | head -1; then + HAS_ALGORITHM=true +fi + +# 条件3:检查是否有数据库操作 +HAS_DATABASE=false +if find src/main/java -name "*.java" -exec grep -l "JdbcTemplate\|JPA\|MyBatis\|@Repository\|@Entity" {} \; 2>/dev/null | head -1; then + HAS_DATABASE=true +fi + +# 决策:生成哪种性能测试 +if [ "$PERFORMANCE_NEEDED" = true ]; then + if [ "$HAS_HTTP_API" = true ]; then + GENERATE_JMETER_TEST=true + elif [ "$HAS_ALGORITHM" = true ]; then + GENERATE_JUNIT_PERF_TEST=true + elif [ "$HAS_DATABASE" = true ]; then + GENERATE_JDBC_PERF_TEST=true + else + GENERATE_LIGHTWEIGHT_PERF_TEST=true + fi +fi +``` + +--- + ### 4.1 性能测试工具选择 | 工具 | 适用语言 | 类型 | 说明 | @@ -937,86 +1457,1235 @@ class BubbleSortUser(HttpUser): assert response.status_code == 200 ``` -### 4.4 性能测试执行命令 +--- -**JMeter CLI执行**: -```bash -# 非GUI模式执行JMeter测试 -jmeter -n -t performance/bubble-sort-test.jmx \ - -l performance/results/test-results.jtl \ - -e -o performance/results/html-report +### 4.4 算法/方法性能测试(JUnit)🆕 -# 参数说明: -# -n: 非GUI模式 -# -t: 测试计划文件 -# -l: 结果日志文件 -# -e: 生成报告 -# -o: 报告输出目录 -``` +**适用场景**:算法类、工具类、排序、计算等方法 -**Locust执行**: -```bash -# 命令行模式执行Locust测试 -locust -f performance/locustfile.py \ - --headless \ - --users 100 \ - --spawn-rate 10 \ - --run-time 60s \ - --host http://localhost:8080 \ - --csv performance/results/locust-results +**生成条件**:检测到`*Sort*.java`、`*Util*.java`、`*Algorithm*.java`等文件 -# 参数说明: -# --headless: 无Web界面 -# --users: 模拟用户数 -# --spawn-rate: 每秒启动用户数 -# --run-time: 运行时长 -# --host: 目标主机 -# --csv: 结果文件前缀 -``` +**Java JUnit性能测试模板**: ---- +```java +package com.example.performance; -## 第5步:测试代码合并 +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; -### 5.1 检测现有测试代码 +import com.example.algorithms.BubbleSort; -**扫描现有测试文件**: -```bash -# 查找已存在的测试文件 -find src/test -name "*Test.java" -o -name "*Steps.java" -find tests -name "test_*.py" -o -name "*_steps.py" -``` +@DisplayName("性能测试") +@Tag("performance") +class BubbleSortPerformanceTest { -### 5.2 合并策略 + @Test + @DisplayName("[@performance] 基础性能验证 - 小规模数据") + void testBasicPerformance_SmallData() { + // Given: 准备小规模测试数据 + int[] smallData = {5, 2, 8, 1, 9}; + int iterations = 1000; + + // When: 执行多次并测量平均时间 + long startTime = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) { + int[] testData = smallData.clone(); + BubbleSort.sort(testData); + } + long endTime = System.currentTimeMillis(); -| 场景 | 策略 | -|-----|------| -| 测试文件不存在 | 直接创建新文件 | -| 测试文件已存在 | 追加新测试方法到文件末尾 | -| 测试方法已存在 | 跳过(不重复生成) | -| Step Definition已存在 | 合并到现有类 | + // Then: 验证平均执行时间 + long avgTime = (endTime - startTime) / iterations; + assertTrue(avgTime < 1, // 1ms阈值 + String.format("小规模数据平均执行时间%dms,超过阈值1ms", avgTime)); + } -**合并逻辑示例**: -```java -// 检测现有测试方法 -Set existingMethods = Arrays.stream(testClass.getMethods()) - .map(Method::getName) - .collect(Collectors.toSet()); + @Test + @DisplayName("[@performance] 中等规模数据性能测试") + void testPerformance_MediumData() { + // Given: 准备中等规模测试数据 + int[] mediumData = generateRandomArray(100); + int iterations = 100; + + // When: 执行多次并测量平均时间 + long startTime = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) { + int[] testData = mediumData.clone(); + BubbleSort.sort(testData); + } + long endTime = System.currentTimeMillis(); -// 只生成不存在的方法 -for (MethodDescription method : methodsToGenerate) { - if (!existingMethods.contains(method.getName())) { - generateTestMethod(method); - } else { - logger.info("跳过已存在的方法: {}", method.getName()); + // Then: 验证平均执行时间 + long avgTime = (endTime - startTime) / iterations; + assertTrue(avgTime < 10, // 10ms阈值 + String.format("中等规模数据平均执行时间%dms,超过阈值10ms", avgTime)); + + // And: 验证结果正确性 + assertTrue(isSorted(mediumData), "排序结果应该正确"); + } + + @Test + @DisplayName("[@performance] 大规模数据性能测试") + void testPerformance_LargeData() { + // Given: 准备大规模测试数据 + int[] largeData = generateRandomArray(1000); + + // When: 执行并测量总时间 + long startTime = System.currentTimeMillis(); + BubbleSort.sort(largeData); + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // Then: 验证总执行时间 + assertTrue(duration < 500, // 500ms阈值 + String.format("大规模数据执行时间%dms,超过阈值500ms", duration)); + + // And: 验证结果正确性 + assertTrue(isSorted(largeData), "排序结果应该正确"); + } + + @Test + @DisplayName("[@performance] 极端情况性能测试 - 逆序数组") + void testPerformance_WorstCase() { + // Given: 准备逆序数组(冒泡排序的最坏情况) + int[] worstCaseData = new int[100]; + for (int i = 0; i < 100; i++) { + worstCaseData[i] = 100 - i; + } + + // When: 执行并测量时间 + long startTime = System.currentTimeMillis(); + BubbleSort.sort(worstCaseData); + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // Then: 验证在合理时间内完成 + assertTrue(duration < 1000, // 1秒阈值 + String.format("最坏情况执行时间%dms,超过阈值1000ms", duration)); + } + + // 辅助方法 + private int[] generateRandomArray(int size) { + java.util.Random random = new java.util.Random(42); + int[] array = new int[size]; + for (int i = 0; i < size; i++) { + array[i] = random.nextInt(10000); + } + return array; + } + + private boolean isSorted(int[] array) { + for (int i = 0; i < array.length - 1; i++) { + if (array[i] > array[i + 1]) { + return false; + } + } + return true; } } ``` -### 5.3 合并执行 +**性能阈值参考**: -```bash -# 合并Step Definitions +| 数据规模 | 时间阈值 | 迭代次数 | 说明 | +|---------|---------|---------|------| +| 10元素 | 1ms | 1000次 | 小规模快速响应 | +| 100元素 | 10ms | 100次 | 中等规模可接受 | +| 1000元素 | 500ms | 1次 | 大规模性能要求 | +| 逆序100元素 | 1000ms | 1次 | 最坏情况验证 | + +--- + +### 4.5 数据库性能测试(JDBC)🆕 + +**适用场景**:包含数据库CRUD操作 + +**生成条件**:检测到`JPA`、`MyBatis`、`@Repository`、`@Entity`等 + +**数据库性能测试模板**: + +```java +package com.example.performance; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import com.example.repository.UserRepository; +import com.example.entity.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@SpringBootTest +@DisplayName("数据库性能测试") +@Tag("performance") +class DatabasePerformanceTest { + + @Autowired + private UserRepository userRepository; + + @Test + @DisplayName("[@performance] 单条查询性能测试") + @Transactional + void testSingleQueryPerformance() { + // Given: 准备测试数据 + Long userId = 1L; + + // When: 执行多次查询并测量时间 + int iterations = 100; + long startTime = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) { + User user = userRepository.findById(userId).orElse(null); + } + long endTime = System.currentTimeMillis(); + + // Then: 验证平均查询时间 + long avgTime = (endTime - startTime) / iterations; + assertTrue(avgTime < 50, // 50ms阈值 + String.format("单条查询平均耗时%dms,超过阈值50ms", avgTime)); + } + + @Test + @DisplayName("[@performance] 批量查询性能测试") + @Transactional + void testBatchQueryPerformance() { + // Given: 准备测试数据 + int batchSize = 100; + + // When: 执行批量查询并测量时间 + long startTime = System.currentTimeMillis(); + List users = userRepository.findAll(); + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // Then: 验证查询时间 + assertTrue(duration < 500, // 500ms阈值 + String.format("批量查询耗时%dms,超过阈值500ms", duration)); + + // And: 验证结果不为空 + assertFalse(users.isEmpty(), "应该返回查询结果"); + } + + @Test + @DisplayName("[@performance] 插入操作性能测试") + @Transactional + void testInsertPerformance() { + // Given: 准备测试数据 + int insertCount = 50; + List users = generateTestUsers(insertCount); + + // When: 执行批量插入并测量时间 + long startTime = System.currentTimeMillis(); + for (User user : users) { + userRepository.save(user); + } + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // Then: 验证插入时间 + assertTrue(duration < 1000, // 1秒阈值 + String.format("批量插入%d条记录耗时%dms,超过阈值1000ms", insertCount, duration)); + } + + // 辅助方法 + private List generateTestUsers(int count) { + List users = new java.util.ArrayList<>(); + for (int i = 0; i < count; i++) { + User user = new User(); + user.setUsername("testuser" + i); + user.setEmail("test" + i + "@example.com"); + users.add(user); + } + return users; + } +} +``` + +--- + +### 4.6 默认轻量级性能测试 🆕 + +**适用场景**:未检测到明确的性能需求,使用默认策略 + +**轻量级性能测试模板**: + +```java +@Test +@DisplayName("[@performance] 默认性能验证") +@Tag("performance") +public void testDefaultPerformance() { + // Given: 准备常规测试数据 + {TestData} data = createTestData(); + + // When: 执行方法并测量时间 + long startTime = System.currentTimeMillis(); + {ClassName}.{methodName}(data); + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // Then: 验证在合理时间内完成(5秒默认阈值) + assertTrue(duration < 5000, + String.format("方法执行耗时%dms,超过默认阈值5000ms", duration)); + + // And: 验证结果正确性 + {验证结果正确性的断言} +} +``` + +**Python轻量级性能测试模板**: + +```python +def test_default_performance(): + """默认性能验证""" + # Given: 准备常规测试数据 + data = create_test_data() + + # When: 执行方法并测量时间 + start_time = time.time() + {module}.{function}(data) + end_time = time.time() + duration = (end_time - start_time) * 1000 # 转换为毫秒 + + # Then: 验证在合理时间内完成(5秒默认阈值) + assert duration < 5000, f"方法执行耗时{duration}ms,超过默认阈值5000ms" + + # And: 验证结果正确性 + {验证结果正确性的断言} +``` + +--- + +### 4.7 性能测试执行命令 + +**JMeter CLI执行**: +```bash +# 非GUI模式执行JMeter测试 +jmeter -n -t performance/bubble-sort-test.jmx \ + -l performance/results/test-results.jtl \ + -e -o performance/results/html-report + +# 参数说明: +# -n: 非GUI模式 +# -t: 测试计划文件 +# -l: 结果日志文件 +# -e: 生成报告 +# -o: 报告输出目录 +``` + +**Locust执行**: +```bash +# 命令行模式执行Locust测试 +locust -f performance/locustfile.py \ + --headless \ + --users 100 \ + --spawn-rate 10 \ + --run-time 60s \ + --host http://localhost:8080 \ + --csv performance/results/locust-results + +# 参数说明: +# --headless: 无Web界面 +# --users: 模拟用户数 +# --spawn-rate: 每秒启动用户数 +# --run-time: 运行时长 +# --host: 目标主机 +# --csv: 结果文件前缀 +``` + +--- + +### 4.8 备选性能测试脚本生成(JMeter未安装时)🆕 + +**适用场景**:HTTP接口项目 + JMeter未安装 + +**核心思路**:当JMeter未安装时,自动生成shell/curl或Python/requests脚本作为备选性能测试方案 + +#### 4.8.1 Shell脚本方案(使用curl) + +**适用项目**:Java项目、Python项目(通用) + +**生成条件**: +```bash +# 检测是否需要生成备选脚本 +if [ "$PERFORMANCE_NEEDED" = true ] && [ "$PROJECT_TYPE" = "http_api" ] && [ ! command -v jmeter ]; then + GENERATE_FALLBACK_SCRIPT=true +fi +``` + +**Shell脚本模板**: + +```bash +#!/bin/bash +# HTTP接口性能测试脚本(备选方案 - JMeter未安装时使用) +# +# 生成时间: {timestamp} +# 项目类型: HTTP接口 +# 工具: curl (系统自带) + +set -e + +# ==================== 配置参数 ==================== +API_BASE_URL="${API_BASE_URL:-http://localhost:8080}" +API_ENDPOINT="${API_ENDPOINT:-/api/sort}" +CONCURRENT_REQUESTS=${CONCURRENT_REQUESTS:-10} +TOTAL_REQUESTS=${TOTAL_REQUESTS:-100} +REQUEST_TIMEOUT=${REQUEST_TIMEOUT:-10} +RESULTS_FILE="${RESULTS_FILE:-performance-test-results.txt}" + +# ==================== 打印配置信息 ==================== +echo "========================================" +echo "HTTP接口性能测试(备选方案)" +echo "========================================" +echo "API地址: $API_BASE_URL$API_ENDPOINT" +echo "并发请求数: $CONCURRENT_REQUESTS" +echo "总请求数: $TOTAL_REQUESTS" +echo "请求超时(秒): $REQUEST_TIMEOUT" +echo "========================================" +echo "" + +# ==================== 初始化统计变量 ==================== +TOTAL_SUCCESS_COUNT=0 +TOTAL_FAILURE_COUNT=0 +TOTAL_RESPONSE_TIME=0 +START_TIME=$(date +%s) + +# ==================== 执行并发请求 ==================== +echo "开始执行并发性能测试..." + +for ((i=1; i<=CONCURRENT_REQUESTS; i++)); do + ( + SUCCESS_COUNT=0 + FAILURE_COUNT=0 + RESPONSE_TIME_SUM=0 + + # 每个线程执行的请求数 + REQUESTS_PER_THREAD=$((TOTAL_REQUESTS / CONCURRENT_REQUESTS)) + + for ((j=1; j<=REQUESTS_PER_THREAD; j++)); do + # 记录开始时间(毫秒) + START_TIME_MS=$(date +%s%3N) + + # 发起HTTP POST请求 + # 注意:根据实际API调整请求方法和数据格式 + RESPONSE=$(curl -s -w "\n%{http_code}\n%{time_total}\n%{size_download}" \ + -X POST "$API_BASE_URL$API_ENDPOINT" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -d '{"array":[1,2,3,4,5]}' \ + --max-time $REQUEST_TIMEOUT \ + 2>&1) + + # 记录结束时间(毫秒) + END_TIME_MS=$(date +%s%N) + + # 解析响应 + HTTP_CODE=$(echo "$RESPONSE" | head -n 1) + TIME_TOTAL=$(echo "$RESPONSE" | tail -n 2 | cut -d'.' -f1) + SIZE_DOWNLOAD=$(echo "$RESPONSE" | tail -n 1) + + # 计算响应时间(毫秒) + RESPONSE_TIME_MS=$((END_TIME_MS - START_TIME_MS)) + + RESPONSE_TIME_SUM=$((RESPONSE_TIME_SUM + RESPONSE_TIME_MS)) + + # 统计成功/失败 + if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then + SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) + else + FAILURE_COUNT=$((FAILURE_COUNT + 1)) + fi + + # 简单的进度指示(每10个请求显示一次) + if [ $((j % 10)) -eq 0 ]; then + echo " 进程 $i: 已完成 $j/$REQUESTS_PER_THREAD 请求" + fi + done + + # 计算该线程的平均响应时间 + if [ $REQUESTS_PER_THREAD -gt 0 ]; then + AVG_RESPONSE_TIME=$((RESPONSE_TIME_SUM / REQUESTS_PER_THREAD)) + else + AVG_RESPONSE_TIME=0 + fi + + # 输出线程结果 + echo " 进程 $i 完成: 成功=$SUCCESS_COUNT, 失败=$FAILURE_COUNT, 平均响应=${AVG_RESPONSE_TIME}ms" + + # 累计到全局统计(通过临时文件传递) + echo "$SUCCESS_COUNT $FAILURE_COUNT $AVG_RESPONSE_TIME" >> "/tmp/perf_temp_$$.txt" + + ) & # 后台执行 + + # 短暂等待,避免进程创建过快 + sleep 0.1 +done + +# ==================== 等待所有后台进程完成 ==================== +wait + +# ==================== 汇总统计 ==================== +END_TIME=$(date +%s) +TOTAL_DURATION=$((END_TIME - START_TIME)) + +# 读取所有线程的统计结果 +if [ -f "/tmp/perf_temp_$$.txt" ]; then + while read -r line; do + thread_success=$(echo "$line" | awk '{print $1}') + thread_failure=$(echo "$line" | awk '{print $2}') + thread_avg_time=$(echo "$line" | awk '{print $3}') + + TOTAL_SUCCESS_COUNT=$((TOTAL_SUCCESS_COUNT + thread_success)) + TOTAL_FAILURE_COUNT=$((TOTAL_FAILURE_COUNT + thread_failure)) + TOTAL_RESPONSE_TIME=$((TOTAL_RESPONSE_TIME + thread_avg_time)) + done < "/tmp/perf_temp_$$.txt" + rm -f "/tmp/perf_temp_$$.txt" +fi + +# 计算总体平均响应时间 +if [ $CONCURRENT_REQUESTS -gt 0 ]; then + OVERALL_AVG_RESPONSE_TIME=$((TOTAL_RESPONSE_TIME / CONCURRENT_REQUESTS)) +else + OVERALL_AVG_RESPONSE_TIME=0 +fi + +# 计算吞吐量(每秒请求数) +TOTAL_REQUESTS_ACTUAL=$((TOTAL_SUCCESS_COUNT + TOTAL_FAILURE_COUNT)) +if [ $TOTAL_DURATION -gt 0 ]; then + THROUGHPUT=$((TOTAL_REQUESTS_ACTUAL * 1000 / TOTAL_DURATION)) +else + THROUGHPUT=0 +fi + +# 计算成功率 +if [ $TOTAL_REQUESTS_ACTUAL -gt 0 ]; then + SUCCESS_RATE=$((TOTAL_SUCCESS_COUNT * 100 / TOTAL_REQUESTS_ACTUAL)) +else + SUCCESS_RATE=0 +fi + +# ==================== 输出测试结果 ==================== +echo "" +echo "========================================" +echo "性能测试结果汇总" +echo "========================================" +echo "总请求数: $TOTAL_REQUESTS_ACTUAL" +echo "成功请求数: $TOTAL_SUCCESS_COUNT" +echo "失败请求数: $TOTAL_FAILURE_COUNT" +echo "成功率: ${SUCCESS_RATE}%" +echo "总耗时: ${TOTAL_DURATION}ms" +echo "平均响应时间: ${OVERALL_AVG_RESPONSE_TIME}ms" +echo "吞吐量: ${THROUGHPUT} 请求/秒" +echo "========================================" + +# ==================== 判断测试是否通过 ==================== +PERFORMANCE_TEST_PASSED=true + +# 检查成功率阈值(要求 > 95%) +if [ $SUCCESS_RATE -lt 95 ]; then + echo "❌ 性能测试失败:成功率 ${SUCCESS_RATE}% 低于95%阈值" + PERFORMANCE_TEST_PASSED=false +fi + +# 检查平均响应时间阈值(要求 < 1000ms) +if [ $OVERALL_AVG_RESPONSE_TIME -gt 1000 ]; then + echo "❌ 性能测试失败:平均响应时间 ${OVERALL_AVG_RESPONSE_TIME}ms 超过1000ms阈值" + PERFORMANCE_TEST_PASSED=false +fi + +echo "" +if [ $PERFORMANCE_TEST_PASSED = true ]; then + echo "✅ 性能测试通过" +else + echo "❌ 性能测试失败" +fi +echo "" + +# 保存结果到文件 +cat > "$RESULTS_FILE" < dict: + """获取统计摘要""" + total = self.success_count + self.failure_count + avg_time = self.total_response_time / total if total > 0 else 0 + success_rate = (self.success_count * 100 / total) if total > 0 else 0 + + return { + "total_requests": total, + "success_count": self.success_count, + "failure_count": self.failure_count, + "success_rate": success_rate, + "avg_response_time_ms": avg_time + } + + +def send_request(config: PerformanceConfig, thread_id: int, + request_id: int, stats: PerformanceStats) -> None: + """ + 发送单个HTTP请求 + + Args: + config: 性能测试配置 + thread_id: 线程ID + request_id: 请求ID + stats: 性能统计对象 + """ + try: + # 准备请求体 + payload = {"array": [i for i in range(1, 6)]} # 示例数据 + + # 记录开始时间 + start_time = time.time() + + # 发送HTTP POST请求 + response = requests.post( + f"{config.api_base_url}{config.api_endpoint}", + json=payload, + timeout=config.request_timeout + ) + + # 记录结束时间 + end_time = time.time() + response_time_ms = int((end_time - start_time) * 1000) + + # 判断请求是否成功 + success = response.status_code in [200, 201] + + # 如果开启详细模式,输出每个请求的结果 + if config.verbose: + status = "成功" if success else f"失败(HTTP {response.status_code})" + print(f" Thread {thread_id}, Request {request_id}: {status}, Time={response_time_ms}ms") + + stats.add_result(success, response_time) + + except requests.exceptions.Timeout: + if config.verbose: + print(f" Thread {thread_id}, Request {request_id}: 超时") + stats.add_result(False, 10000) # 超时记为10秒 + except Exception as e: + if config.verbose: + print(f" Thread {thread_id}, Request {request_id}: 异常 - {e}") + stats.add_result(False, 0) + + +def worker_thread(config: PerformanceConfig, thread_id: int, + stats: PerformanceStats) -> None: + """ + 工作线程函数 + + Args: + config: 性能测试配置 + thread_id: 线程ID + stats: 性能统计对象 + """ + requests_per_thread = config.total_requests // config.concurrent_threads + + for request_id in range(1, requests_per_thread + 1): + send_request(config, thread_id, request_id, stats) + + +def run_performance_test(config: PerformanceConfig) -> Tuple[dict, PerformanceStats]: + """ + 执行性能测试 + + Args: + config: 性能测试配置 + + Returns: + (测试结果字典, 性能统计对象) + """ + stats = PerformanceStats() + + print(f"开始执行HTTP接口性能测试...") + print(f" API地址: {config.api_base_url}{config.api_endpoint}") + print(f" 并发线程数: {config.concurrent_threads}") + print(f" 总请求数: {config.total_requests}") + print(f" 超时时间: {config.request_timeout}秒") + print("") + + start_time = time.time() + + # 创建并启动工作线程 + threads = [] + for thread_id in range(config.concurrent_threads): + thread = threading.Thread( + target=worker_thread, + args=(config, thread_id, stats) + ) + threads.append(thread) + thread.start() + + # 等待所有线程完成 + for thread in threads: + thread.join() + + end_time = time.time() + total_duration = int((end_time - start_time) * 1000) + + print(f"性能测试完成,总耗时: {total_duration}ms") + print("") + + # 获取统计摘要 + summary = stats.get_summary() + summary["total_duration_ms"] = total_duration + + # 计算吞吐量 + if total_duration > 0: + summary["throughput_per_second"] = summary["total_requests"] * 1000 / total_duration + else: + summary["throughput_per_second"] = 0 + + return summary, stats + + +def main(): + """主函数""" + parser = argparse.ArgumentParser(description="HTTP接口性能测试(备选方案)") + parser.add_argument("--url", default="http://localhost:8080", help="API基础URL") + parser.add_argument("--endpoint", default="/api/sort", help="API端点路径") + parser.add_argument("--concurrent", type=int, default=10, help="并发线程数") + parser.add_argument("--requests", type=int, default=100, help="总请求数") + parser.add_argument("--timeout", type=int, default=10, help="请求超时(秒)") + parser.add_argument("--verbose", action="store_true", help="详细输出模式") + + args = parser.parse_args() + + # 创建配置 + config = PerformanceConfig( + api_base_url=args.url, + api_endpoint=args.endpoint, + concurrent_threads=args.concurrent, + total_requests=args.requests, + request_timeout=args.timeout, + verbose=args.verbose + ) + + # 执行性能测试 + summary, stats = run_performance_test(config) + + # ==================== 输出结果 ==================== + print("=" * 60) + print("性能测试结果汇总") + print("=" * 60) + print(f"总请求数: {summary['total_requests']}") + print(f"成功请求数: {summary['success_count']}") + print(f"失败请求数: {summary['failure_count']}") + print(f"成功率: {summary['success_rate']:.2f}%") + print(f"总耗时: {summary['total_duration_ms']}ms") + print(f"平均响应时间: {summary['avg_response_time_ms']:.2f}ms") + print(f"吞吐量: {summary['throughput_per_second']:.2f} 请求/秒") + print("=" * 60) + print("") + + # 判断测试是否通过 + passed = summary['success_rate'] >= 95 and summary['avg_response_time_ms'] < 1000 + + if passed: + print("✅ 性能测试通过") + else: + print("❌ 性能测试失败") + if summary['success_rate'] < 95: + print(f" 原因: 成功率 {summary['success_rate']:.2f}% 低于95%阈值") + if summary['avg_response_time_ms'] >= 1000: + print(f" 原因: 平均响应时间 {summary['avg_response_time_ms']:.2f}ms 超过1000ms阈值") + + return 0 if passed else 1 + + +if __name__ == "__main__": + exit(main()) +``` + +--- + +#### 4.8.3 自动生成备选脚本的逻辑 + +**在生成性能测试代码时添加此逻辑**: + +```bash +# 检查是否需要生成备选脚本 +if [ "$PERFORMANCE_NEEDED" = true ] && [ "$PROJECT_TYPE" = "http_api" ]; then + echo " → 检查JMeter安装状态..." + + if command -v jmeter &> /dev/null; then + echo " ✅ JMeter已安装,生成JMeter测试计划" + # 生成JMeter测试计划(保持原有逻辑) + else + echo " ⚠️ JMeter未安装,生成备选性能测试脚本" + + # 根据项目类型选择脚本语言 + if [ -f "pom.xml" ] || [ -f "build.gradle" ]; then + # Java项目 → 生成shell脚本 + cat > src/test/scripts/performance-test.sh << 'SHELL_SCRIPT' + elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then + # Python项目 → 生成Python脚本 + cat > tests/performance/test_http_api.py << 'PYTHON_SCRIPT' + fi + + echo " ✅ 备选性能测试脚本已生成" + + # 设置脚本可执行权限(对于shell脚本) + if [ -f "src/test/scripts/performance-test.sh" ]; then + chmod +x src/test/scripts/performance-test.sh + fi + fi +fi +``` + +--- + +#### 4.8.4 备选脚本命名规则 + +| 项目类型 | 脚本类型 | 输出路径 | +|---------|---------|---------| +| Java | Shell脚本 | `src/test/scripts/performance-test.sh` | +| Python | Python脚本 | `tests/performance/test_http_api.py` | +| 通用 | Shell脚本 | `performance/performance-test.sh` | + +--- + +## 第4.8步:生成远程curl测试用例 🆕 + +**目标**:生成用于测试远端部署服务的 curl 测试脚本,支持本地执行远端请求。 + +### 4.8.1 读取部署配置 + +**配置文件位置**:`.claude/config/deployment-config.json` + +```bash +CONFIG_FILE=".claude/config/deployment-config.json" + +# 检查配置文件是否存在 +if [ ! -f "$CONFIG_FILE" ]; then + echo "⚠️ 部署配置文件不存在: $CONFIG_FILE" + echo "跳过远程curl测试生成" +else + # 读取配置 + BASE_URL=$(jq -r '.remoteServer.baseUrl' $CONFIG_FILE) + API_BASE_PATH=$(jq -r '.remoteServer.apiBasePath' $CONFIG_FILE) + ENABLED=$(jq -r '.remoteServer.enabled' $CONFIG_FILE) + + if [ "$ENABLED" != "true" ]; then + echo "⚠️ 远端服务未启用" + echo "跳过远程curl测试生成" + else + echo "✅ 远端服务配置: $BASE_URL" + echo "✅ API基础路径: $API_BASE_PATH" + # 继续生成curl测试脚本(将使用上述配置值) + fi +fi +``` + +**🔴 P0级强制要求**: + +在生成 `remote-api-test.sh` 脚本时,**必须**将读取到的配置值填充到脚本中: +- `${BASE_URL}` → 替换为实际读取的 baseUrl 值(如:`http://192.168.1.100:8080`) +- `${API_BASE_PATH}` → 替换为实际读取的 apiBasePath 值(如:`/api/v1`) + +**禁止使用硬编码的 localhost 值!** + +### 4.8.2 解析 API 接口 + +**从 Feature 文件提取 API 接口**: + +```bash +# 扫描 Feature 文件中的 HTTP 请求模式 +grep -E "When (I send|I make|I call)" dev/active/*/features/*.feature | \ + sed -E 's/.* (GET|POST|PUT|DELETE|PATCH) \/([^ ]+).*/\1 \2/' | \ + sort -u +``` + +**从测试用例文档提取接口定义**: + +```bash +# 提取 API 接口定义 +grep -E "(接口|API|Endpoint):" docs/*/testing/*_测试用例.md +``` + +### 4.8.3 生成 curl 测试脚本 🔴 **必须使用从 deployment-config.json 读取的配置** + +**重要**:脚本模板中的 BASE_URL、API_BASE_PATH 必须使用从配置文件读取的实际值,**不得使用硬编码的 localhost**! + +**🔴 P0级强制生成流程**: + +```bash +# 第1步:读取配置(已在4.8.1完成) +CONFIG_FILE=".claude/config/deployment-config.json" +BASE_URL=$(jq -r '.remoteServer.baseUrl' $CONFIG_FILE) +API_BASE_PATH=$(jq -r '.remoteServer.apiBasePath' $CONFIG_FILE) + +# 第2步:生成脚本时,将配置值直接写入脚本 +# 使用 sed 或 heredoc 将实际值替换到脚本中 + +cat > src/test/scripts/remote-api-test.sh << EOF +#!/bin/bash +# 远端API测试脚本 +# 🔴 配置来源:.claude/config/deployment-config.json + +set -e + +# 🔴 远端服务配置 - 实际值从配置文件读取 +BASE_URL="${BASE_URL}" # 🔴 替换为实际值,如:http://192.168.1.100:8080 +API_BASE_PATH="${API_BASE_PATH}" # 🔴 替换为实际值,如:/api/v1 + +echo "📌 远端服务配置:" +echo " BASE_URL: \$BASE_URL" +echo " API_BASE_PATH: \$API_BASE_PATH" +echo "" + +# 其余脚本内容... +EOF + +chmod +x src/test/scripts/remote-api-test.sh +``` + +**示例:生成的脚本(假设配置文件中的 baseUrl 是 `http://192.168.1.100:8080`)**: + +```bash +#!/bin/bash +# 远端API测试脚本 +# 🔴 配置来源:.claude/config/deployment-config.json + +set -e + +# 🔴 远端服务配置 - 实际值从配置文件读取 +BASE_URL="http://192.168.1.100:8080" # ✅ 使用配置文件中的真实地址 +API_BASE_PATH="/api/v1" # ✅ 使用配置文件中的真实路径 + +echo "📌 远端服务配置:" +echo " BASE_URL: $BASE_URL" +echo " API_BASE_PATH: $API_BASE_PATH" +echo "" +``` + +**❌ 错误示例(禁止使用)**: + +```bash +# ❌ 错误:硬编码localhost +BASE_URL="http://localhost:8080" +API_BASE_PATH="/api" +``` + +--- + +**Java 项目 - Shell 脚本完整模板**: + +`src/test/scripts/remote-api-test.sh`: +```bash +#!/bin/bash +# 远端API测试脚本 +# 自动生成于: $(date) +# 🔴 配置来源:.claude/config/deployment-config.json + +set -e + +# 🔴 远端服务配置 - 从 deployment-config.json 读取的实际值 +# ⚠️ 不得使用硬编码的 localhost,必须使用配置文件中的真实地址 +BASE_URL="${BASE_URL}" # 从 deployment-config.json 的 remoteServer.baseUrl 读取 +API_BASE_PATH="${API_BASE_PATH}" # 从 deployment-config.json 的 remoteServer.apiBasePath 读取 + +# 颜色输出 +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 测试结果统计 +TOTAL=0 +PASSED=0 +FAILED=0 + +# 测试函数 +test_api() { + local method=$1 + local endpoint=$2 + local data=$3 + local expected_code=$4 + + TOTAL=$((TOTAL + 1)) + url="${BASE_URL}${API_BASE_PATH}${endpoint}" + + echo -e "\n${YELLOW}测试 ${TOTAL}: ${method} ${url}${NC}" + + if [ -z "$data" ]; then + response=$(curl -s -w "\n%{http_code}" -X ${method} "${url}") + else + response=$(curl -s -w "\n%{http_code}" -X ${method} "${url}" \ + -H "Content-Type: application/json" \ + -d "${data}") + fi + + http_code=$(echo "$response" | tail -n1) + body=$(echo "$response" | head -n -1) + + if [ "$http_code" = "$expected_code" ]; then + echo -e "${GREEN}✅ 通过${NC} (HTTP $http_code)" + PASSED=$((PASSED + 1)) + else + echo -e "${RED}❌ 失败${NC} (HTTP $http_code, 期望 $expected_code)" + echo "响应: $body" + FAILED=$((FAILED + 1)) + fi +} + +# API 测试用例(根据实际接口添加) +echo -e "\n${YELLOW}=== API 测试 ===${NC}" + +# 示例: GET /users +test_api "GET" "/users" "" "200" + +# 示例: POST /users +test_api "POST" "/users" '{"name":"test","email":"test@example.com"}' "201" + +# 示例: GET /users/{id} +test_api "GET" "/users/1" "" "200" + +# 输出测试结果 +echo -e "\n${YELLOW}=== 测试结果汇总 ===${NC}" +echo "总计: $TOTAL" +echo -e "${GREEN}通过: $PASSED${NC}" +echo -e "${RED}失败: $FAILED${NC}" + +if [ $FAILED -gt 0 ]; then + exit 1 +fi +``` + +**Python 项目 - Python 脚本模板**: + +`tests/scripts/remote_api_test.py`: +```python +#!/usr/bin/env python3 +""" +远端API测试脚本 +自动生成于: $(date) +""" + +import requests +import json +import sys +from typing import Optional, Dict + +# 远端服务配置 +BASE_URL = "http://localhost:8080" +API_BASE_PATH = "/api" + +# 测试结果统计 +total = 0 +passed = 0 +failed = 0 + + +def test_api(method: str, endpoint: str, data: Optional[Dict] = None, + expected_code: int = 200) -> None: + """执行API测试""" + global total, passed, failed + + total += 1 + url = f"{BASE_URL}{API_BASE_PATH}{endpoint}" + + print(f"\n测试 {total}: {method} {url}") + + try: + if data: + response = requests.request( + method=method, + url=url, + json=data, + headers={"Content-Type": "application/json"}, + timeout=30 + ) + else: + response = requests.request( + method=method, + url=url, + timeout=30 + ) + + if response.status_code == expected_code: + print(f"✅ 通过 (HTTP {response.status_code})") + passed += 1 + else: + print(f"❌ 失败 (HTTP {response.status_code}, 期望 {expected_code})") + print(f"响应: {response.text}") + failed += 1 + + except Exception as e: + print(f"❌ 异常: {e}") + failed += 1 + + +def main(): + """主测试流程""" + print("\n=== API 测试 ===") + + # 示例: GET /users + test_api("GET", "/users", None, 200) + + # 示例: POST /users + test_api("POST", "/users", {"name": "test", "email": "test@example.com"}, 201) + + # 示例: GET /users/{id} + test_api("GET", "/users/1", None, 200) + + # 输出测试结果 + print("\n=== 测试结果汇总 ===") + print(f"总计: {total}") + print(f"通过: {passed}") + print(f"失败: {failed}") + + if failed > 0: + sys.exit(1) + + +if __name__ == "__main__": + main() +``` + +### 4.8.4 集成到测试执行 + +在第6步(执行测试)中,自动执行 curl 测试脚本: + +```bash +# 检查并执行远程curl测试 +if [ -f "src/test/scripts/remote-api-test.sh" ]; then + echo "执行远端API测试..." + chmod +x src/test/scripts/remote-api-test.sh + bash src/test/scripts/remote-api-test.sh +elif [ -f "tests/scripts/remote_api_test.py" ]; then + echo "执行远端API测试..." + python tests/scripts/remote_api_test.py +fi +``` + +--- + +## 第5步:测试代码合并 + +### 5.1 检测现有测试代码 + +**扫描现有测试文件**: +```bash +# 查找已存在的测试文件 +find src/test -name "*Test.java" -o -name "*Steps.java" +find tests -name "test_*.py" -o -name "*_steps.py" +``` + +### 5.2 合并策略 + +| 场景 | 策略 | +|-----|------| +| 测试文件不存在 | 直接创建新文件 | +| 测试文件已存在 | 追加新测试方法到文件末尾 | +| 测试方法已存在 | 跳过(不重复生成) | +| Step Definition已存在 | 合并到现有类 | + +**合并逻辑示例**: +```java +// 检测现有测试方法 +Set existingMethods = Arrays.stream(testClass.getMethods()) + .map(Method::getName) + .collect(Collectors.toSet()); + +// 只生成不存在的方法 +for (MethodDescription method : methodsToGenerate) { + if (!existingMethods.contains(method.getName())) { + generateTestMethod(method); + } else { + logger.info("跳过已存在的方法: {}", method.getName()); + } +} +``` + +### 5.3 合并执行 + +```bash +# 合并Step Definitions if [ -f "src/test/java/cucumber/steps/BubbleSortSteps.java" ]; then echo "检测到现有Step Definitions,执行合并..." # 备份原文件 @@ -1047,6 +2716,10 @@ fi 3. 性能测试 (压力测试) └─> JMeter / locust └─> 执行时间: 5-10分钟 + +4. 远程API测试 (接口测试) 🆕 + └─> curl / requests + └─> 执行时间: 1-3分钟 ``` ### 6.2 测试执行脚本 @@ -1086,43 +2759,199 @@ if [ "$TEST_COUNT" -eq 0 ]; then fi echo "✅ 找到 $TEST_COUNT 个测试类" -# 步骤1: 单元测试(移除 -DfailIfNoTests=false,确保无测试时失败) +# 步骤1: 单元测试 echo "" -echo "[1/3] 执行单元测试..." +echo "[1/4] 执行单元测试..." mvn test -Dtest="*Test" 2>&1 | tee "$REPORT_DIR/unit-test.log" UNIT_TEST_STATUS=$? if [ $UNIT_TEST_STATUS -ne 0 ]; then - echo "❌ 单元测试执行失败(退出码: $UNIT_TEST_STATUS)" - echo "请查看日志: $REPORT_DIR/unit-test.log" - exit 1 + echo "⚠️ 单元测试执行失败(退出码: $UNIT_TEST_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/unit-test.log" + echo "💡 继续执行其他测试..." +else + echo "✅ 单元测试执行完成" fi -echo "✅ 单元测试执行完成" # 步骤2: Cucumber测试 echo "" -echo "[2/3] 执行Cucumber场景测试..." +echo "[2/4] 执行Cucumber场景测试..." mvn verify -DskipUnitTests 2>&1 | tee "$REPORT_DIR/cucumber-test.log" CUCUMBER_STATUS=$? if [ $CUCUMBER_STATUS -ne 0 ]; then - echo "❌ Cucumber测试执行失败(退出码: $CUCUMBER_STATUS)" - echo "请查看日志: $REPORT_DIR/cucumber-test.log" - exit 1 + echo "⚠️ Cucumber测试执行失败(退出码: $CUCUMBER_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/cucumber-test.log" + echo "💡 继续执行其他测试..." +else + echo "✅ Cucumber测试执行完成" fi -echo "✅ Cucumber测试执行完成" # 步骤3: 性能测试 echo "" -echo "[3/3] 执行性能测试..." -if [ -f "performance/test-plan.jmx" ]; then - jmeter -n -t performance/test-plan.jmx \ - -l "$REPORT_DIR/performance-results.jtl" \ - -e -o "$REPORT_DIR/performance-html" - PERFORMANCE_STATUS=$? +echo "[3/4] 执行性能测试..." + +PERFORMANCE_FOUND=false +PERFORMANCE_PASSED=false + +# 3.1 检查JUnit性能测试(优先) +echo " → 检测JUnit性能测试..." +if grep -r "@Tag(\"performance\")\|@Tag(\"performance\"\)"\|@performance" src/test/java 2>/dev/null | head -1; then + echo " ✅ 检测到JUnit性能测试" + + # 执行JUnit性能测试(不跳过无测试的情况) + mvn test -Dtest="*Performance*" -DfailIfNoTests=false 2>&1 | tee "$REPORT_DIR/performance-test.log" + JUNIT_PERF_STATUS=$? + + # 退出码0表示测试通过,254表示没有测试被运行 + if [ $JUNIT_PERF_STATUS -eq 0 ] || [ $JUNIT_PERF_STATUS -eq 254 ]; then + PERFORMANCE_FOUND=true + PERFORMANCE_PASSED=true + echo " ✅ JUnit性能测试执行完成" + else + PERFORMANCE_FOUND=true + PERFORMANCE_PASSED=false + echo " ❌ JUnit性能测试执行失败(退出码: $JUNIT_PERF_STATUS)" + fi else - echo "⚠️ 未找到性能测试计划,跳过性能测试" + echo " ⚠️ 未检测到JUnit性能测试" +fi + +# 3.2 检查JMeter测试计划(如果JUnit性能测试不存在或失败) +if [ ! $PERFORMANCE_FOUND ] || [ ! $PERFORMANCE_PASSED ]; then + echo " → 检测JMeter测试计划..." + + if [ -f "performance/test-plan.jmx" ]; then + echo " ✅ 检测到JMeter测试计划" + + if command -v jmeter &> /dev/null; then + jmeter -n -t performance/test-plan.jmx \ + -l "$REPORT_DIR/performance-results.jtl" \ + -e -o "$REPORT_DIR/performance-html" 2>&1 | tee "$REPORT_DIR/jmeter-test.log" + JMETER_STATUS=$? + + PERFORMANCE_FOUND=true + if [ $JMETER_STATUS -eq 0 ]; then + PERFORMANCE_PASSED=true + echo " ✅ JMeter性能测试执行完成" + else + PERFORMANCE_PASSED=false + echo " ❌ JMeter性能测试执行失败(退出码: $JMETER_STATUS)" + fi + else + echo " ⚠️ JMeter未安装,尝试执行备选性能测试脚本..." + + # 3.2.1 检查并执行Shell备选脚本 🆕 + if [ -f "src/test/scripts/performance-test.sh" ]; then + echo " ✅ 检测到Shell备选性能测试脚本" + chmod +x src/test/scripts/performance-test.sh + src/test/scripts/performance-test.sh 2>&1 | tee "$REPORT_DIR/fallback-performance-test.log" + FALLBACK_STATUS=$? + + PERFORMANCE_FOUND=true + if [ $FALLBACK_STATUS -eq 0 ]; then + PERFORMANCE_PASSED=true + echo " ✅ 备选性能测试执行完成" + else + PERFORMANCE_PASSED=false + echo " ❌ 备选性能测试执行失败(退出码: $FALLBACK_STATUS)" + fi + # 3.2.2 检查Python备选脚本 + elif [ -f "tests/performance/test_http_api.py" ]; then + echo " ✅ 检测到Python备选性能测试脚本" + python3 tests/performance/test_http_api.py 2>&1 | tee "$REPORT_DIR/fallback-performance-test.log" + FALLBACK_STATUS=$? + + PERFORMANCE_FOUND=true + if [ $FALLBACK_STATUS -eq 0 ]; then + PERFORMANCE_PASSED=true + echo " ✅ 备选性能测试执行完成" + else + PERFORMANCE_PASSED=false + echo " ❌ 备选性能测试执行失败(退出码: $FALLBACK_STATUS)" + fi + else + echo " ⚠️ 未找到备选性能测试脚本" + fi + fi + else + echo " ⚠️ 未找到JMeter测试计划" + fi +fi + +# 3.3 性能测试结果汇总 +echo "" +if [ ! $PERFORMANCE_FOUND ]; then + echo "⚠️ 未检测到任何性能测试(JUnit或JMeter)" + echo "💡 建议:添加性能测试用例以验证系统性能" + PERFORMANCE_STATUS=0 # 不阻断,仅警告 +elif [ $PERFORMANCE_PASSED = true ]; then PERFORMANCE_STATUS=0 + echo "✅ 性能测试通过" +else + PERFORMANCE_STATUS=1 + echo "❌ 性能测试失败" +fi + +# 步骤4: 远程API测试 🆕 +echo "" +echo "[4/4] 执行远程API测试..." + +API_TEST_FOUND=false +API_TEST_PASSED=false + +# 检查并执行Shell脚本 +if [ -f "src/test/scripts/remote-api-test.sh" ]; then + echo "✅ 检测到远程API测试脚本(Shell)" + API_TEST_FOUND=true + + chmod +x src/test/scripts/remote-api-test.sh + bash src/test/scripts/remote-api-test.sh 2>&1 | tee "$REPORT_DIR/remote-api-test.log" + API_TEST_STATUS=$? + + if [ $API_TEST_STATUS -eq 0 ]; then + API_TEST_PASSED=true + echo "✅ 远程API测试通过" + else + echo "⚠️ 远程API测试失败(退出码: $API_TEST_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/remote-api-test.log" + fi +# 检查并执行Python脚本 +elif [ -f "tests/scripts/remote_api_test.py" ]; then + echo "✅ 检测到远程API测试脚本(Python)" + API_TEST_FOUND=true + + python3 tests/scripts/remote_api_test.py 2>&1 | tee "$REPORT_DIR/remote-api-test.log" + API_TEST_STATUS=$? + + if [ $API_TEST_STATUS -eq 0 ]; then + API_TEST_PASSED=true + echo "✅ 远程API测试通过" + else + echo "⚠️ 远程API测试失败(退出码: $API_TEST_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/remote-api-test.log" + fi +else + echo "⚠️ 未找到远程API测试脚本" + echo "💡 建议:" + echo " 1. 确保 deployment-config.json 中 remoteServer.enabled = true" + echo " 2. 检查是否已生成远程API测试脚本:" + echo " - src/test/scripts/remote-api-test.sh(Java项目)" + echo " - tests/scripts/remote_api_test.py(Python项目)" + API_TEST_STATUS=0 # 不阻断,仅警告 +fi + +# 远程API测试结果汇总 +echo "" +if [ ! $API_TEST_FOUND ]; then + echo "⚠️ 未执行远程API测试(脚本不存在)" + API_TEST_STATUS=0 # 不阻断,仅警告 +elif [ $API_TEST_PASSED = true ]; then + API_TEST_STATUS=0 + echo "✅ 远程API测试通过" +else + API_TEST_STATUS=1 + echo "⚠️ 远程API测试失败(请确认远端服务已部署并运行)" fi # 汇总结果 @@ -1130,11 +2959,67 @@ echo "" echo "========================================" echo "测试执行完成" echo "========================================" -echo "单元测试: ✅ 通过" -echo "Cucumber: ✅ 通过" -echo "性能测试: $([ $PERFORMANCE_STATUS -eq 0 ] && echo '✅ 完成' || echo '❌ 失败')" + +# 显示每个测试的状态 +if [ $UNIT_TEST_STATUS -eq 0 ]; then + echo "单元测试: ✅ 通过" +else + echo "单元测试: ❌ 失败" +fi + +if [ $CUCUMBER_STATUS -eq 0 ]; then + echo "Cucumber: ✅ 通过" +else + echo "Cucumber: ❌ 失败" +fi + +if [ $PERFORMANCE_STATUS -eq 0 ]; then + echo "性能测试: ✅ 完成" +else + echo "性能测试: ❌ 失败" +fi + +if [ $API_TEST_STATUS -eq 0 ]; then + echo "远程API测试: ✅ 完成" +else + echo "远程API测试: ⚠️ 失败" +fi + echo "" echo "详细报告: $REPORT_DIR/" + +# 统一判断:所有测试都通过才算成功 🆕 +OVERALL_STATUS=0 + +if [ $UNIT_TEST_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +if [ $CUCUMBER_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +if [ $PERFORMANCE_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +if [ $API_TEST_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +echo "" +if [ $OVERALL_STATUS -eq 0 ]; then + echo "========================================" + echo "✅ 所有测试通过" + echo "========================================" +else + echo "========================================" + echo "⚠️ 部分测试失败,请查看详细报告" + echo "========================================" +fi + +# 最终退出码 +exit $OVERALL_STATUS ``` **Python项目执行脚本**: @@ -1142,7 +3027,10 @@ echo "详细报告: $REPORT_DIR/" #!/bin/bash # test-runner.sh - Python测试执行脚本 -set -e +# 🔴 重要配置: +# - 不使用 set -e,让所有测试都能执行完毕 +# - 使用 pipefail 确保管道中命令失败时能正确捕获退出码 +set -o pipefail REPORT_DIR="test-results" mkdir -p "$REPORT_DIR" @@ -1153,39 +3041,284 @@ echo "========================================" # 步骤1: 单元测试 echo "" -echo "[1/3] 执行单元测试..." +echo "[1/4] 执行单元测试..." pytest tests/unit/ \ -v \ --junitxml="$REPORT_DIR/unit-test.xml" \ --html="$REPORT_DIR/unit-test.html" \ | tee "$REPORT_DIR/unit-test.log" +UNIT_TEST_STATUS=${PIPESTATUS[0]} + +if [ $UNIT_TEST_STATUS -ne 0 ]; then + echo "⚠️ 单元测试执行失败(退出码: $UNIT_TEST_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/unit-test.log" + echo "💡 继续执行其他测试..." +else + echo "✅ 单元测试执行完成" +fi # 步骤2: behave测试 echo "" -echo "[2/3] 执行behave场景测试..." +echo "[2/4] 执行behave场景测试..." behave features/ \ -f json \ -o "$REPORT_DIR/cucumber-report.json" \ -f html \ -o "$REPORT_DIR/cucumber-report.html" \ | tee "$REPORT_DIR/behave-test.log" +CUCUMBER_STATUS=${PIPESTATUS[0]} + +if [ $CUCUMBER_STATUS -ne 0 ]; then + echo "⚠️ behave测试执行失败(退出码: $CUCUMBER_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/behave-test.log" + echo "💡 继续执行其他测试..." +else + echo "✅ behave测试执行完成" +fi -# 步骤3: locust性能测试 +# 步骤3: 性能测试 echo "" -echo "[3/3] 执行性能测试..." -locust -f performance/locustfile.py \ - --headless \ - --users 100 \ - --spawn-rate 10 \ - --run-time 60s \ - --host http://localhost:8080 \ - --csv "$REPORT_DIR/locust-results" \ - --html "$REPORT_DIR/locust-report.html" +echo "[3/4] 执行性能测试..." + +PERFORMANCE_FOUND=false +PERFORMANCE_PASSED=false + +# 3.1 检查pytest性能测试(优先) +echo " → 检测pytest性能测试..." +if find tests/ -name "*.py" -exec grep -l "mark.performance\|@performance\|@pytest.mark.performance" {} \; 2>/dev/null | head -1; then + echo " ✅ 检测到pytest性能测试" + + # 执行pytest性能测试 + pytest tests/ -m performance -v \ + --junitxml="$REPORT_DIR/performance-test.xml" \ + --html="$REPORT_DIR/performance-test.html" \ + 2>&1 | tee "$REPORT_DIR/performance-test.log" + PYTEST_PERF_STATUS=$? + + # 退出码0表示测试通过,5表示没有测试被收集 + if [ $PYTEST_PERF_STATUS -eq 0 ] || [ $PYTEST_PERF_STATUS -eq 5 ]; then + PERFORMANCE_FOUND=true + PERFORMANCE_PASSED=true + echo " ✅ pytest性能测试执行完成" + else + PERFORMANCE_FOUND=true + PERFORMANCE_PASSED=false + echo " ❌ pytest性能测试执行失败(退出码: $PYTEST_PERF_STATUS)" + fi +else + echo " ⚠️ 未检测到pytest性能测试" +fi +# 3.2 检查locust测试(如果pytest性能测试不存在或失败) +if [ ! $PERFORMANCE_FOUND ] || [ ! $PERFORMANCE_PASSED ]; then + echo " → 检测locust测试..." + + if [ -f "performance/locustfile.py" ]; then + echo " ✅ 检测到locust测试" + + if pip show locust > /dev/null 2>&1; then + # 使用较低并发数和较短时间,避免测试时间过长 + locust -f performance/locustfile.py \ + --headless \ + --users 10 \ + --spawn-rate 1 \ + --run-time 10s \ + --host http://localhost:8080 \ + --csv "$REPORT_DIR/locust-results" \ + --html "$REPORT_DIR/locust-report.html" \ + 2>&1 | tee "$REPORT_DIR/locust-test.log" + LOCUST_STATUS=$? + + PERFORMANCE_FOUND=true + if [ $LOCUST_STATUS -eq 0 ]; then + PERFORMANCE_PASSED=true + echo " ✅ Locust性能测试执行完成" + else + PERFORMANCE_PASSED=false + echo " ❌ Locust性能测试执行失败(退出码: $LOCUST_STATUS)" + fi + else + echo " ⚠️ locust未安装,尝试执行备选性能测试脚本..." + + # 3.2.1 检查并执行Python备选脚本 🆕 + if [ -f "tests/performance/test_http_api.py" ]; then + echo " ✅ 检测到Python备选性能测试脚本" + python3 tests/performance/test_http_api.py 2>&1 | tee "$REPORT_DIR/fallback-performance-test.log" + FALLBACK_STATUS=$? + + PERFORMANCE_FOUND=true + if [ $FALLBACK_STATUS -eq 0 ]; then + PERFORMANCE_PASSED=true + echo " ✅ 备选性能测试执行完成" + else + PERFORMANCE_PASSED=false + echo " ❌ 备选性能测试执行失败(退出码: $FALLBACK_STATUS)" + fi + # 3.2.2 检查Shell备选脚本 + elif [ -f "performance/performance-test.sh" ]; then + echo " ✅ 检测到Shell备选性能测试脚本" + chmod +x performance/performance-test.sh + performance/performance-test.sh 2>&1 | tee "$REPORT_DIR/fallback-performance-test.log" + FALLBACK_STATUS=$? + + PERFORMANCE_FOUND=true + if [ $FALLBACK_STATUS -eq 0 ]; then + PERFORMANCE_PASSED=true + echo " ✅ 备选性能测试执行完成" + else + PERFORMANCE_PASSED=false + echo " ❌ 备选性能测试执行失败(退出码: $FALLBACK_STATUS)" + fi + else + echo " ⚠️ 未找到备选性能测试脚本" + fi + fi + else + echo " ⚠️ 未找到locust测试文件" + fi +fi + +# 3.3 性能测试结果汇总 +echo "" +if [ ! $PERFORMANCE_FOUND ]; then + echo "⚠️ 未检测到任何性能测试(pytest或locust)" + echo "💡 建议:添加性能测试用例以验证系统性能" + PERFORMANCE_STATUS=0 # 不阻断,仅警告 +elif [ $PERFORMANCE_PASSED = true ]; then + PERFORMANCE_STATUS=0 + echo "✅ 性能测试通过" +else + PERFORMANCE_STATUS=1 + echo "❌ 性能测试失败" +fi + +# 步骤4: 远程API测试 🆕 +echo "" +echo "[4/4] 执行远程API测试..." + +API_TEST_FOUND=false +API_TEST_PASSED=false + +# 检查并执行Python脚本 +if [ -f "tests/scripts/remote_api_test.py" ]; then + echo "✅ 检测到远程API测试脚本(Python)" + API_TEST_FOUND=true + + python3 tests/scripts/remote_api_test.py 2>&1 | tee "$REPORT_DIR/remote-api-test.log" + API_TEST_STATUS=$? + + if [ $API_TEST_STATUS -eq 0 ]; then + API_TEST_PASSED=true + echo "✅ 远程API测试通过" + else + echo "⚠️ 远程API测试失败(退出码: $API_TEST_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/remote-api-test.log" + fi +# 检查并执行Shell脚本 +elif [ -f "src/test/scripts/remote-api-test.sh" ]; then + echo "✅ 检测到远程API测试脚本(Shell)" + API_TEST_FOUND=true + + chmod +x src/test/scripts/remote-api-test.sh + bash src/test/scripts/remote-api-test.sh 2>&1 | tee "$REPORT_DIR/remote-api-test.log" + API_TEST_STATUS=$? + + if [ $API_TEST_STATUS -eq 0 ]; then + API_TEST_PASSED=true + echo "✅ 远程API测试通过" + else + echo "⚠️ 远程API测试失败(退出码: $API_TEST_STATUS)" + echo "📄 请查看日志: $REPORT_DIR/remote-api-test.log" + fi +else + echo "⚠️ 未找到远程API测试脚本" + echo "💡 建议:" + echo " 1. 确保 deployment-config.json 中 remoteServer.enabled = true" + echo " 2. 检查是否已生成远程API测试脚本:" + echo " - tests/scripts/remote_api_test.py(Python项目)" + echo " - src/test/scripts/remote-api-test.sh(Java项目)" + API_TEST_STATUS=0 # 不阻断,仅警告 +fi + +# 远程API测试结果汇总 +echo "" +if [ ! $API_TEST_FOUND ]; then + echo "⚠️ 未执行远程API测试(脚本不存在)" + API_TEST_STATUS=0 # 不阻断,仅警告 +elif [ $API_TEST_PASSED = true ]; then + API_TEST_STATUS=0 + echo "✅ 远程API测试通过" +else + API_TEST_STATUS=1 + echo "⚠️ 远程API测试失败(请确认远端服务已部署并运行)" +fi + +# 汇总结果 🆕 echo "" echo "========================================" echo "测试执行完成" +echo "========================================" + +# 显示每个测试的状态 +if [ $UNIT_TEST_STATUS -eq 0 ]; then + echo "单元测试: ✅ 通过" +else + echo "单元测试: ❌ 失败" +fi + +if [ $CUCUMBER_STATUS -eq 0 ]; then + echo "behave: ✅ 通过" +else + echo "behave: ❌ 失败" +fi + +if [ $PERFORMANCE_STATUS -eq 0 ]; then + echo "性能测试: ✅ 完成" +else + echo "性能测试: ❌ 失败" +fi + +if [ $API_TEST_STATUS -eq 0 ]; then + echo "远程API测试: ✅ 完成" +else + echo "远程API测试: ⚠️ 失败" +fi + +echo "" echo "详细报告: $REPORT_DIR/" + +# 统一判断:所有测试都通过才算成功 🆕 +OVERALL_STATUS=0 + +if [ $UNIT_TEST_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +if [ $CUCUMBER_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +if [ $PERFORMANCE_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +if [ $API_TEST_STATUS -ne 0 ]; then + OVERALL_STATUS=1 +fi + +echo "" +if [ $OVERALL_STATUS -eq 0 ]; then + echo "========================================" + echo "✅ 所有测试通过" + echo "========================================" +else + echo "========================================" + echo "⚠️ 部分测试失败,请查看详细报告" + echo "========================================" +fi + +# 最终退出码 +exit $OVERALL_STATUS ``` --- @@ -1743,11 +3876,16 @@ public class TestReportGenerator { 📄 报告: test-results/cucumber-test.log [3/3] 执行性能测试... -✅ 性能测试完成 -📊 性能指标: - - 吞吐量: 150 req/s - - 平均响应时间: 320ms - - 错误率: 0% + → 检测JUnit性能测试... + ✅ 检测到JUnit性能测试(2个方法) + ✅ 性能测试通过 + 📄 报告: test-results/performance-test.log + +📊 性能测试结果: + - testBasicPerformance_SmallData: ✅ 通过(平均0.5ms) + - testPerformance_MediumData: ✅ 通过(平均8ms) + - testPerformance_LargeData: ✅ 通过(总耗时125ms) + - testPerformance_WorstCase: ✅ 通过(总耗时450ms) 📄 验证结果已生成: docs/dev/testing/bubble-sort_自动化测试验证结果.md @@ -1774,6 +3912,13 @@ public class TestReportGenerator { - ✅ **方法名/函数名必须使用英文,禁止使用中文** - ✅ **Step Definition方法名使用语义化英文(如given/when/then前缀)** +性能测试必须满足 🆕: +- ✅ **除非需求明确声明无需性能测试,否则必须生成性能测试代码** +- ✅ **性能测试必须包含时间测量和阈值验证** +- ✅ **性能测试必须验证结果正确性(不仅仅是速度)** +- ✅ **性能测试结果必须包含在验证结果报告中** +- ✅ **支持多种性能测试类型**(HTTP接口/算法方法/数据库/默认轻量级) + 验证结果必须满足 🆕: - ✅ 从Cucumber JSON报告中提取缺陷信息 - ✅ 缺陷报告包含:缺陷ID、严重程度、来源、失败步骤、错误信息 @@ -1782,6 +3927,51 @@ public class TestReportGenerator { --- +## 🔄 自动触发测试代码Review 🆕 + +测试执行完成后,**强烈建议**执行测试代码完整性检查: + +### 方式1:自动触发(推荐) + +```bash +/test-code-reviewer +``` + +这将: +1. 🔍 检查测试代码是否为空或只有TODO +2. 🔍 识别假阳性断言(如`assertTrue(true)`) +3. 📊 分析测试覆盖率 +4. 🎯 生成质量评分和Review报告 +5. ❌ 如果发现空测试,标记为**阻断**而非**pass** + +### 为什么要Review? + +| 问题 | 风险 | Review作用 | +|-----|------|----------| +| 空实现 | 测试未真实验证,但显示"通过" | 识别并标记为阻断 | +| 假阳性断言 | 测试永远通过,无法发现缺陷 | 识别并报告问题 | +| 无断言 | 测试执行但无验证 | 提示添加断言 | +| 覆盖缺失 | 部分场景未测试 | 报告缺失的测试 | + +### 输出示例 + +```markdown +🔍 测试代码Review完成 + +📊 Review统计: +- 扫描文件: 3个 +- 检查方法: 15个 +- 发现问题: 2个 + - 🔴 P0级: 1个(空实现) + - 🟠 P1级: 1个(无断言) + +📈 质量评分: 85/100 (B) + +📄 Review报告已生成: docs/dev/testing/bubble-sort_代码Review.md +``` + +--- + ## 注意事项 1. **不生成功能实现代码** - 只生成测试代码,假定功能代码已存在 diff --git a/.claude/skills/functional-test-generator/SKILL.md b/.claude/skills/functional-test-generator/SKILL.md index fb17fc7cedfb9e5ef806f6012d1e497793f57eb1..435f6e77a70ac0f7df861095c94dc77a5e9d0fff 100644 --- a/.claude/skills/functional-test-generator/SKILL.md +++ b/.claude/skills/functional-test-generator/SKILL.md @@ -2,15 +2,26 @@ name: functional-test-generator type: functional-test-generator description: 测试用例生成专家,基于代码变更与接口定义自动生成覆盖关键路径、边界与异常场景的测试用例文档和Wemind导入格式文件 -version: 3.3 +version: 3.5 author: DevSyncAgent Team -last_updated: 2026-01-28 +last_updated: 2026-02-08 sync_info: sync_partner: .claude/agents/testing/functional-test-generator.md sync_config: .claude/config/agent-skill-sync-rules.json sync_strategy: bidirectional note: "本文件与Agent文件保持双向同步,修改时请同步更新对应文件" changelog: + v3.5 - 2026-02-08 + - 🆕 新增第0.7步:子需求模式检测与处理 + - 🔄 支持DevOps自动循环中的bug fix子需求 + - 🔄 子需求模式:基于父需求测试用例修改/新增,不重新生成 + - 🔄 从cycle-state.json读取parentRequirementId和subRequirementType + - 🔄 标记子需求专属测试用例为【子需求新增】 + - 🔄 测试代码标记@Tag("sub-requirement") + v3.4 - 2026-02-02 + - 🆕 新增第0.1步:检查测试生成状态,避免在DevOps循环中重复生成 + - 🆕 支持从 test-status.json 读取已生成的测试用例文档和代码路径 + - 🆕 添加循环模式下的跳过逻辑 v3.3 - 2026-01-28 - 🆕 新增"下一步建议"章节 - 引导用户调用 /automated-test-executor 进入第5阶段(测试执行) @@ -186,6 +197,63 @@ graph TD | 第2步 | 所有来源 | 测试用例文档 | 生成最终文档 | | 第2.5步 🆕v3.3 | 测试用例文档 | Wemind导入文件 | 转换为Wemind格式 | +### 第0.1步:检查测试生成状态 🆕 + +**目标**:检查测试用例文档和代码是否已生成,避免在循环中重复生成 + +**检查逻辑**: + +```python +task_name = get_task_name() # 从上下文获取任务名称 +status_file = f"dev/active/{task_name}/test-status.json" + +if os.path.exists(status_file): + with open(status_file) as f: + status = json.load(f) + + test_cases_generated = status.get("testCasesGenerated", False) + test_code_generated = status.get("testCodeGenerated", False) + + if test_cases_generated and test_code_generated: + # 测试用例文档和代码都已生成 + print("✅ 测试用例文档和代码已生成,跳过生成步骤") + print("📁 测试用例文档:", status.get("paths", {}).get("testCaseDoc", "")) + print("📁 测试代码:", ", ".join(status.get("paths", {}).get("testCode", []))) + + # 直接跳到下一步(第5步:下一步建议) + skip_to_next_step() + return + else: + print("⚠️ 测试用例文档和代码生成未完成,继续生成") +else: + print("⚠️ 首次执行,将生成测试用例文档和代码") +``` + +**状态文件结构**: + +```json +{ + "taskName": "user-registration", + "testCasesGenerated": true, + "testCodeGenerated": true, + "generatedAt": "2026-02-02T10:00:00", + "paths": { + "testCaseDoc": "docs/dev/testing/user-registration_测试用例.md", + "testCode": [ + "src/test/java/cucumber/", + "src/test/scripts/remote-test.sh" + ] + } +} +``` + +**检查位置**: +- 在第0.2步之前执行 +- 如果已生成且循环中,跳过整个生成流程 +- 如果未生成或首次执行,继续正常流程 + +--- + ### 第0.2步:检查远程仓库状态 🆕 **目标**:确保基于最新代码工作,避免冲突 @@ -763,6 +831,94 @@ when(userService.createUser(any(UserCreateDTO.class))) --- +### 第0.7步:子需求模式检测与处理 🆕v3.5 + +**目标**:检测当前需求是否为DevOps循环中的bug fix子需求,并相应调整测试生成策略 + +#### 检测逻辑 + +```markdown +1. 检查 cycle-state.json 是否存在 + IF 存在 THEN + 读取以下字段: + - parentRequirementId: 父需求ID + - subRequirementType: 子需求类型(应为 "bug-fix") + - relatedTestCases: 关联的失败测试用例列表 + + IF parentRequirementId 存在 AND subRequirementType == "bug-fix" THEN + 进入【子需求模式】 + ELSE + 进入【标准模式】 + END IF +ELSE + 进入【标准模式】 +END IF +``` + +#### 子需求模式处理策略 + +当检测到子需求模式时: + +**1. 读取父需求测试用例文档** +```markdown +路径:docs/{branch}/testing/{父需求功能名}_测试用例.md +``` + +**2. 读取父需求测试代码** +```markdown +路径:src/test/java/**/*.java 或 src/test/**/*.py +``` + +**3. 生成测试用例修改方案** +- ✅ **不重新生成**完整的测试用例文档 +- ✅ **基于父需求测试用例**进行**修改/新增** +- 📝 标记新增/修改的测试用例为【子需求新增】 + +**4. 生成测试代码修改方案** +- ✅ **不重新生成**完整的测试代码文件 +- ✅ **基于父需求测试代码**进行**修改/新增** +- 📝 标记新增/修改的测试方法为 `@Tag("sub-requirement")` + +**5. 输出格式差异** + +| 维度 | 标准模式 | 子需求模式 | +|-----|---------|-----------| +| 测试用例文档 | 生成完整文档 | 基于父需求修改/新增 | +| 测试代码 | 生成完整代码文件 | 基于父需求修改/新增 | +| 输出文件 | {功能名}_测试用例.md | {父需求名}_测试用例_修改.md | +| 测试标记 | 无 | @Tag("sub-requirement") | + +#### 子需求模式提示卡片 + +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔄 **子需求模式检测**(DevOps自动循环) + +检测到当前需求为bug fix子需求: +- 父需求ID: {parentRequirementId} +- 子需求类型: bug-fix +- 关联失败用例: {relatedTestCases} + +📋 **测试生成策略**: +- ✅ 基于父需求测试用例修改/新增 +- ✅ 基于父需求测试代码修改/新增 +- 📝 标记子需求专属测试用例 + +> 📌 父需求测试用例:{父需求测试用例路径} +> 📌 父需求测试代码:{父需求测试代码路径} +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +#### 降级处理 + +如果 cycle-state.json 不存在或缺少必需字段,自动降级到标准模式: + +```markdown +⚠️ 未检测到子需求信息,使用标准测试生成模式 +``` + +--- + ### 第1.5步:静态代码分析与场景推导 🆕v3.3 **目标**:通过静态代码分析推导测试场景,确保覆盖关键路径、边界和异常场景 @@ -1441,6 +1597,51 @@ git commit -m "#AI commit# 测试阶段:新增功能 - {功能名}" --- +## 🔄 自动触发测试用例文档Review 🆕 + +测试用例文档生成完成后,**强烈建议**执行文档完整性检查: + +### 方式1:自动触发(推荐) + +```bash +/test-case-document-reviewer +``` + +这将: +1. 📋 检查验收标准覆盖率(每个AC是否都有对应测试用例) +2. 🎯 检查功能点完整性(所有功能是否都有测试覆盖) +3. 🔍 检查边界场景(空值、null、极值等) +4. ⚠️ 检查异常场景(参数校验、权限、资源不存在等) +5. 🔗 检测冗余用例(重复或高度相似的测试) +6. 📝 提供优化建议(新增/修改/删除) + +### 为什么要Review测试用例文档? + +| 问题 | 风险 | Review作用 | +|-----|------|----------| +| 验收标准未覆盖 | 需求未被测试,存在质量风险 | 识别并报告缺失的AC | +| 缺少边界测试 | 边界条件下的缺陷 | 提示补充边界用例 | +| 缺少异常测试 | 异常处理不完善 | 提示补充异常用例 | +| 冗余用例 | 测试效率低,维护成本高 | 建议删除或合并 | + +### 输出示例 + +```markdown +🔍 测试用例文档Review完成 + +📊 Review统计: +- 检查文档: 2个(测试用例 + 需求) +- 测试用例: 15个 +- 发现问题: 2个 + - 🟠 P1级: 2个(边界场景缺失) + +📈 质量评分: 90/100 (A) - 优秀 + +📄 Review报告已生成: docs/dev/testing/xxx_测试用例文档Review.md +``` + +--- + ## 🎯 下一步建议 🆕 ### 方式1:继续执行自动化测试(推荐)⭐ diff --git a/.claude/skills/health-check/SKILL.md b/.claude/skills/health-check/SKILL.md new file mode 100644 index 0000000000000000000000000000000000000000..c6b6e260bd972bd6dec9cfcddb57881709da7685 --- /dev/null +++ b/.claude/skills/health-check/SKILL.md @@ -0,0 +1,358 @@ +--- +name: health-check +type: testing +description: 远端服务健康检查专家,通过轮询健康接口确认服务部署状态 +version: 1.1 +author: DevSyncAgent Team +last_updated: 2026-02-08 +changelog: + v1.1 - 2026-02-08 + - 🔧 移除对healthCheckPath配置的依赖,使用默认值/actuator/health + v1.0 - 2026-02-02 + - 初始版本发布 + - 远端服务健康检查功能 + - 可配置的轮询间隔和重试次数 + - 支持多种HTTP状态码判断 +--- + +# 健康检查Skill + +你是远端服务健康检查专家,负责通过轮询健康接口确认服务是否已成功部署。 + +## 适用场景 + +- CI/CD部署后验证服务状态 +- 自动化测试前确认服务就绪 +- DevOps循环中的部署验证环节 + +## 核心能力 + +| 能力 | 说明 | +|-----|------| +| **配置读取** | 从 `deployment-config.json` 读取远端服务配置 | +| **健康检查** | 通过curl轮询健康接口 | +| **状态判断** | 根据HTTP状态码和响应内容判断服务状态 | +| **进度提示** | 实时显示检查进度和结果 | + +## 输入 + +**配置文件**:`.claude/config/deployment-config.json` + +```json +{ + "remoteServer": { + "baseUrl": "http://localhost:8080", + "enabled": true + }, + "healthCheck": { + "maxRetries": 10, + "retryInterval": 60, + "timeout": 600 + } +} +``` + +**注意**:健康检查路径使用默认值 `/actuator/health`,不再从配置文件读取。 + +## 输出 + +**成功时**: +```markdown +======================================== +健康检查 +======================================== +服务地址: http://localhost:8080 +健康检查: http://localhost:8080/actuator/health +最大重试: 10 次 +重试间隔: 60 秒 +======================================== + +第 1 次检查(15:30:00)... +HTTP状态码: 503 +→ 服务不可达(可能正在部署中) +⏳ 等待 60 秒后重试... + +第 2 次检查(15:31:00)... +HTTP状态码: 200 +服务状态: UP + +======================================== +✅ 健康检查通过 +======================================== +检查次数: 2 +总耗时: 120 秒 + +📌 服务已就绪,可以执行测试 +``` + +**失败时**: +```markdown +======================================== +❌ 健康检查超时 +======================================== +已重试 10 次,服务仍未就绪 + +建议: +1. 检查CI/CD部署状态 +2. 查看远端服务器日志 +3. 确认服务配置正确 +``` + +## 执行流程 + +### Step 1: 读取配置 + +```bash +CONFIG_FILE=".claude/config/deployment-config.json" + +# 检查配置文件是否存在 +if [ ! -f "$CONFIG_FILE" ]; then + echo "❌ 配置文件不存在: $CONFIG_FILE" + echo "请先创建配置文件" + exit 1 +fi + +# 读取配置 +BASE_URL=$(jq -r '.remoteServer.baseUrl' $CONFIG_FILE) +MAX_RETRIES=$(jq -r '.healthCheck.maxRetries' $CONFIG_FILE) +RETRY_INTERVAL=$(jq -r '.healthCheck.retryInterval' $CONFIG_FILE) +ENABLED=$(jq -r '.remoteServer.enabled' $CONFIG_FILE) + +# 健康检查路径使用默认值 +HEALTH_PATH="/actuator/health" + +# 检查是否启用 +if [ "$ENABLED" != "true" ]; then + echo "⚠️ 远端服务未启用" + echo "如需启用,请修改配置文件:remoteServer.enabled = true" + exit 0 +fi +``` + +### Step 2: 构建健康检查URL + +```bash +HEALTH_URL="${BASE_URL}${HEALTH_PATH}" + +echo "========================================" +echo "健康检查" +echo "========================================" +echo "服务地址: $BASE_URL" +echo "健康检查: $HEALTH_URL" +echo "最大重试: $MAX_RETRIES 次" +echo "重试间隔: $RETRY_INTERVAL 秒" +echo "========================================" +echo "" +``` + +### Step 3: 轮询健康接口 + +```bash +for i in $(seq 1 $MAX_RETRIES); do + echo "第 $i 次检查($(date '+%H:%M:%S'))..." + + # 发起健康检查请求 + RESPONSE=$(curl -s -w "\n%{http_code}" "$HEALTH_URL" --max-time 10 2>&1) + HTTP_CODE=$(echo "$RESPONSE" | tail -n 1) + BODY=$(echo "$RESPONSE" | head -n -1) + + echo "HTTP状态码: $HTTP_CODE" + + # 尝试解析JSON响应 + if echo "$BODY" | jq -e . >/dev/null 2>&1; then + STATUS=$(echo "$BODY" | jq -r '.status // empty') + echo "服务状态: $STATUS" + + # 检查状态是否为UP + if [ "$STATUS" = "UP" ]; then + echo "" + echo "========================================" + echo "✅ 健康检查通过" + echo "========================================" + echo "检查次数: $i" + echo "总耗时: $((i * RETRY_INTERVAL)) 秒" + echo "" + echo "📌 服务已就绪,可以执行测试" + exit 0 + fi + fi + + # 根据HTTP状态码判断 + case $HTTP_CODE in + 503) + echo "→ 服务不可达(可能正在部署中)" + ;; + 500) + echo "→ 服务器错误(部署可能失败)" + echo "" + echo "⚠️ 建议检查CI/CD部署日志" + ;; + 502) + echo "→ 网关错误(服务可能未启动)" + ;; + 404) + echo "→ 接口不存在(服务未部署或路径错误)" + ;; + 200) + echo "→ 服务响应正常但状态不是UP" + echo "→ 可能依赖组件异常" + ;; + 000) + echo "→ 连接失败(无法访问服务器)" + ;; + *) + echo "→ 未知响应" + ;; + esac + + # 检查是否继续 + if [ $i -lt $MAX_RETRIES ]; then + # 503可能是部署中,继续轮询 + if [ "$HTTP_CODE" = "503" ] || [ "$HTTP_CODE" = "502" ] || [ "$HTTP_CODE" = "000" ]; then + echo "⏳ 等待 ${RETRY_INTERVAL} 秒后重试..." + sleep $RETRY_INTERVAL + else + # 其他错误,询问是否继续 + echo "" + echo "❓ 检测到非503错误,是否继续轮询?[Y/n]" + read -r response < /dev/tty + if [[ ! $response =~ ^[Yy]$ ]] && [ ! -z "$response" ]]; then + echo "❌ 用户取消健康检查" + exit 1 + fi + sleep $RETRY_INTERVAL + fi + fi + echo "" +done +``` + +### Step 4: 输出超时信息 + +```bash +echo "========================================" +echo "❌ 健康检查超时" +echo "========================================" +echo "已重试 $MAX_RETRIES 次,服务仍未就绪" +echo "" +echo "建议:" +echo "1. 检查CI/CD部署状态" +echo "2. 查看远端服务器日志" +echo "3. 确认服务配置正确" +echo "4. 检查网络连接" + +exit 1 +``` + +## 简化的健康接口示例 + +### Java项目(Spring Boot) + +```java +package com.example.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.HashMap; +import java.util.Map; + +@RestController +public class HealthController { + + @GetMapping("/actuator/health") + public Map health() { + Map response = new HashMap<>(); + response.put("status", "UP"); + return response; + } +} +``` + +### Python项目(Flask) + +```python +from flask import Blueprint, jsonify + +health_bp = Blueprint('health', __name__) + +@health_bp.route('/actuator/health', methods=['GET']) +def health(): + """健康检查接口""" + return jsonify({ + 'status': 'UP' + }) +``` + +## 配置说明 + +### remoteServer 节点 + +| 字段 | 类型 | 默认值 | 说明 | +|-----|------|--------|------| +| baseUrl | string | http://localhost:8080 | 远端服务基础地址 | +| enabled | boolean | true | 是否启用远端服务 | + +**注意**:健康检查路径使用硬编码默认值 `/actuator/health`,不再从配置文件读取。 + +### healthCheck 节点 + +| 字段 | 类型 | 默认值 | 说明 | +|-----|------|--------|------| +| maxRetries | int | 10 | 最大重试次数 | +| retryInterval | int | 60 | 重试间隔(秒) | +| timeout | int | 600 | 总超时时间(秒) | +| successCodes | array | [200, 204] | 成功的HTTP状态码 | +| successStatus | string | UP | 期望的服务状态 | + +### deployment 节点 + +| 字段 | 类型 | 默认值 | 说明 | +|-----|------|--------|------| +| autoDeployEnabled | boolean | true | 是否启用自动部署 | +| waitTimeout | int | 600 | 部署等待超时(秒) | +| maxCycles | int | 5 | 最大循环次数 | + +### testing 节点 + +| 字段 | 类型 | 默认值 | 说明 | +|-----|------|--------|------| +| includeRemoteTests | boolean | true | 是否包含远端测试 | +| remoteTestTimeout | int | 30 | 远端测试超时(秒) | + +## 注意事项 + +1. **配置文件必须存在**:首次使用前必须创建 `deployment-config.json` +2. **健康接口必须返回正确格式**:`{"status": "UP"}` +3. **轮询间隔建议**:根据实际部署时间调整,默认60秒 +4. **网络连接**:确保能访问远端服务地址 + +## 使用示例 + +### 示例1:基本使用 + +```bash +/health-check +``` + +### 示例2:在DevOps流程中使用 + +```bash +# 1. 提交并触发部署 +/git-commit --stage 开发 --type NEW --name 用户注册 --auto-deploy + +# 2. 等待部署完成后,执行健康检查 +/health-check + +# 3. 健康检查通过后,执行测试 +/automated-test-executor +``` + +--- + +## 质量标准 + +- ✅ 必须从配置文件读取服务地址 +- ✅ 必须支持多种HTTP状态码判断 +- ✅ 必须提供友好的进度提示 +- ✅ 必须在503状态时继续轮询 +- ✅ 必须在其他错误时询问用户 diff --git a/.claude/skills/skill-rules.json b/.claude/skills/skill-rules.json index 890d45446ec9fbd443c85c8c6a9116a08e947cb7..57561c329589ba50ee92be8d6630ce837bb621f9 100644 --- a/.claude/skills/skill-rules.json +++ b/.claude/skills/skill-rules.json @@ -36,6 +36,58 @@ "docs/**/testing/*测试执行报告*.md", ".claude/skills/test-report/SKILL.md" ] + }, + "test-code-reviewer": { + "keywordTriggers": [ + "测试代码review", + "test code review", + "测试代码检查", + "test code check", + "review test", + "检查测试", + "测试完整性检查", + "test completeness check", + "测试质量检查", + "test quality check" + ], + "pathPatterns": [ + "src/test/**/*.java", + "src/test/**/*.py", + "tests/**/*.py", + "dev/active/**/features/*.feature", + "docs/**/testing/*测试用例*.md", + "docs/**/testing/*Review*.md", + ".claude/skills/test-code-reviewer/SKILL.md" + ], + "autoTrigger": { + "after": "automated-test-executor", + "condition": "testExecutionComplete" + } + }, + "test-case-document-reviewer": { + "keywordTriggers": [ + "测试用例文档review", + "test case document review", + "测试用例检查", + "test case check", + "测试用例完整性检查", + "test case completeness check", + "测试文档检查", + "test document check", + "测试文档review", + "test document review" + ], + "pathPatterns": [ + "docs/**/testing/*测试用例*.md", + "docs/**/testing/*_test_cases.md", + "docs/**/requirements/*_需求.md", + "docs/**/testing/*DocumentReview*.md", + ".claude/skills/test-case-document-reviewer/SKILL.md" + ], + "autoTrigger": { + "after": "functional-test-generator", + "condition": "documentGenerated" + } } } } diff --git a/.claude/skills/test-case-document-reviewer/SKILL.md b/.claude/skills/test-case-document-reviewer/SKILL.md new file mode 100644 index 0000000000000000000000000000000000000000..8d7592fb9d89ecea64072947095a545c84a5031b --- /dev/null +++ b/.claude/skills/test-case-document-reviewer/SKILL.md @@ -0,0 +1,834 @@ +--- +name: test-case-document-reviewer +type: testing +description: 测试用例文档完整性检查专家,基于需求文档审查测试用例的覆盖率、完整性及边界场景 +version: 1.1 +author: DevSyncAgent Team +last_updated: 2026-02-08 +changelog: + v1.1 - 2026-02-08 + - 🆕 新增子需求模式检测与处理 + - 🔄 支持DevOps自动循环中子需求测试用例审查 + - 🔄 子需求模式:基于父需求测试用例审查修改内容 + - 🔄 从cycle-state.json读取parentRequirementId + - 🔄 审查策略差异化:子需求模式检查修改内容完整性 + v1.0 - 2026-02-02 + - 初始版本 + - 验收标准覆盖率检查 + - 功能点完整性检查 + - 边界场景检查 + - 异常场景检查 + - 冗余检查 + - 优化建议生成 +--- + +# 测试用例文档Review Skill + +你是测试用例文档完整性检查专家,负责审查测试用例文档的质量,基于需求文档验证覆盖率、完整性及边界场景。 + +## 适用场景 + +- 在 `functional-test-generator` 生成测试用例文档后自动检查文档质量 +- 对现有测试用例文档进行完整性审查 +- 识别缺失的测试场景和冗余的测试用例 +- 验证测试用例文档是否符合设计规范 + +## 核心能力 + +| 能力 | 说明 | +|-----|------| +| **验收标准覆盖率检查** | 验证需求文档的每个验收标准都有对应测试用例 | +| **功能点完整性检查** | 检查需求文档的所有功能点是否都有测试覆盖 | +| **边界场景检查** | 识别是否包含必要的边界测试(空值、null、极值等) | +| **异常场景检查** | 检查是否包含异常处理测试 | +| **冗余检查** | 识别重复或高度相似的测试用例 | +| **优化建议** | 提供具体的测试用例优化和补充建议 | + +## 输入 + +**优先级顺序**: + +1. **测试用例文档**(必须): + - 路径:`docs/{branch}/testing/{功能名}_测试用例.md` +2. **需求文档**(必须): + - 路径:`docs/{branch}/requirements/{功能名}_需求.md` +3. **设计文档**(可选): + - 路径:`docs/{branch}/design/{功能名}_设计.md` + +## 输出 + +**主要输出**: +- 📊 **测试用例文档Review报告**(Markdown格式) +- 📝 **优化建议清单**(补充/修改/删除) + +**输出路径**: +``` +docs/{branch}/testing/ +└── {功能名}_测试用例文档Review.md +``` + +## 检查规则 + +### 规则1: 验收标准覆盖率检查(P0) + +从需求文档提取验收标准,检查每个标准是否都有对应测试用例。 + +**检查逻辑**: +```markdown +1. 解析需求文档,提取所有验收标准(AC-xxx) +2. 解析测试用例文档,提取所有测试用例的"来源"字段 +3. 一一对应检查,识别未覆盖的验收标准 +``` + +**扣分**:-20分/个缺失 + +**示例**: +```markdown +需求文档验收标准: +- AC-001: 用户输入用户名和密码,点击登录,登录成功 +- AC-002: 用户输入错误的密码,登录失败 +- AC-003: 用户输入不存在的用户名,提示"用户不存在" + +测试用例文档: +- TC001 → 来源:AC-001 ✅ +- TC002 → 来源:AC-002 ✅ +- ❌ 缺失:AC-003(用户不存在场景) +``` + +--- + +### 规则2: 功能点完整性检查(P0) + +检查需求文档的所有功能点是否都有测试覆盖。 + +**检查逻辑**: +```markdown +1. 解析需求文档的功能描述章节 +2. 识别核心功能和子功能 +3. 检查每个功能是否至少有一个正向测试用例 +``` + +**扣分**:-15分/个缺失 + +**功能点识别规则**: +| 模式 | 说明 | 示例 | +|-----|------|------| +| `支持.*功能` | 功能能力 | "支持用户登录" | +| `可以.*操作` | 操作能力 | "可以修改密码" | +| `提供.*接口` | 接口功能 | "提供查询接口" | +| `实现.*功能` | 实现功能 | "实现数据导出" | + +--- + +### 规则3: 边界场景检查(P1) + +检查是否包含必要的边界测试。 + +**边界类型清单**: + +| 边界类型 | 说明 | 检测方法 | +|---------|------|---------| +| **空值** | 空字符串、空数组、空集合 | 测试数据包含`""`、`[]`、`{}` | +| **null值** | null输入 | 测试数据包含`null` | +| **零值** | 数值0 | 测试数据包含`0` | +| **极值** | 最大/最小值 | 测试数据包含`MAX_VALUE`、`MIN_VALUE` | +| **长度边界** | 字符串/数组长度限制 | 测试数据包含最小/最大长度 | +| **数量边界** | 数量限制(如分页) | 测试数据包含0、1、最大值 | + +**扣分**:-10分/个缺失 + +--- + +### 规则4: 异常场景检查(P1) + +检查是否包含异常处理测试。 + +**异常类型清单**: + +| 异常类型 | 说明 | 示例 | +|---------|------|------| +| **参数校验异常** | 必填参数缺失、格式错误 | 用户名为空、邮箱格式错误 | +| **权限异常** | 无权限访问 | 未登录用户访问受控资源 | +| **资源不存在** | 访问不存在的资源 | 查询不存在的ID | +| **并发冲突** | 并发修改冲突 | 多用户同时修改同一数据 | +| **超时异常** | 操作超时 | 网络超时、数据库超时 | +| **业务规则异常** | 违反业务约束 | 余额不足、库存不足 | + +**扣分**:-10分/个缺失 + +--- + +### 规则5: 冗余检查(P2) + +识别重复或高度相似的测试用例。 + +**冗余类型**: + +| 冗余类型 | 检测方法 | 示例 | +|---------|---------|------| +| **完全重复** | 测试步骤完全相同 | 两个用例步骤完全一致 | +| **高度相似** | 相似度 > 90% | 仅测试数据不同 | +| **包含关系** | 一个用例包含另一个 | 用例A是用例B的子集 | + +**扣分**:-5分/个冗余 + +--- + +## 质量评分 + +### 评分规则 + +**初始分**:100分 + +| 扣分项 | 分值 | 等级 | +|-------|-----:|:----:| +| 验收标准缺失 | -20分/个 | P0 | +| 功能点缺失 | -15分/个 | P0 | +| 边界场景缺失 | -10分/个 | P1 | +| 异常场景缺失 | -10分/个 | P1 | +| 冗余用例 | -5分/个 | P2 | + +**最终等级**: + +| 分数区间 | 等级 | 含义 | 报告状态 | +|---------|-----|------|:--------:| +| 90-100 | A | 优秀 | ✅ 通过 | +| 80-89 | B | 良好 | ✅ 通过 | +| 70-79 | C | 及格 | ⚠️ 警告 | +| 60-69 | D | 需改进 | ⚠️ 警告 | +| <60 | F | 阻断 | ❌ 阻断 | + +**特殊规则**: +- 存在**任何P0级问题** → 自动降为F级(阻断) +- 存在**3个及以上P1级问题** → 最高不超过C级 + +--- + +## 子需求模式检测 🆕v1.1 + +**目标**:检测当前测试用例文档是否为DevOps循环中子需求的修改文档 + +### 检测逻辑 + +```markdown +1. 检查 cycle-state.json 是否存在 + IF 存在 THEN + 读取 parentRequirementId 和 subRequirementType + + IF subRequirementType == "bug-fix" THEN + 进入【子需求审查模式】 + ELSE + 进入【标准审查模式】 + END IF +ELSE + 进入【标准审查模式】 +END IF +``` + +### 子需求审查模式处理策略 + +当检测到子需求模式时: + +**1. 读取父需求测试用例文档** +```markdown +路径:docs/{branch}/testing/{父需求功能名}_测试用例.md +``` + +**2. 审查策略差异** + +| 审查维度 | 标准模式 | 子需求模式 | +|---------|---------|-----------| +| 覆盖率检查 | 检查所有功能点覆盖 | 仅检查新增/修改的用例 | +| 完整性检查 | 检查文档完整性 | 基于父需求文档检查修改内容 | +| 冗余检查 | 检查用例间冗余 | 检查与父需求用例的冗余 | +| 评分标准 | 完整文档评分 | 修改内容评分 | + +**3. 输出调整** +- ✅ 报告中标识子需求模式 +- ✅ 说明基于父需求文档的修改内容 +- ✅ 提供修改建议而非重新生成建议 + +**4. 子需求模式提示** +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔄 **子需求审查模式**(DevOps自动循环) + +检测到当前测试用例为子需求修改文档: +- 父需求ID: {parentRequirementId} +- 审查策略: 基于父需求测试用例审查修改内容 + +📋 **审查重点**: +- ✅ 新增测试用例是否覆盖失败场景 +- ✅ 修改的测试用例是否保持一致性 +- ✅ 与父需求测试用例是否存在冗余 + +> 📌 父需求测试用例:{父需求测试用例路径} +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + +## Review流程 + +```mermaid +graph TD + A[开始] --> B[第1步: 读取测试用例文档] + B --> C[第2步: 读取需求文档] + C --> D[第3步: 执行验收标准覆盖检查] + D --> E[第4步: 执行功能点完整性检查] + E --> F[第5步: 执行边界场景检查] + F --> G[第6步: 执行异常场景检查] + G --> H[第7步: 执行冗余检查] + H --> I[第8步: 计算质量评分] + I --> J[第9步: 生成优化建议] + J --> K[第10步: 生成Review报告] + K --> L{有P0问题?} + L -->|是| M[报告状态: 阻断] + L -->|否| N[报告状态: 通过/警告] + M --> O[结束] + N --> O +``` + +--- + +## 详细步骤 + +### 第1步:读取测试用例文档 + +**目标**:解析测试用例文档,提取所有测试用例信息 + +**提取字段**: +```markdown +- 测试用例ID: TC001, TC002, ... +- 测试用例名称 +- 来源字段: 关联的需求/功能点 +- 测试类型: 单元测试/接口测试/功能测试 +- 优先级: P0/P1/P2/P3 +- 测试步骤 +- 预期结果 +- 测试数据 +``` + +**输出格式**: +```json +{ + "test_cases": [ + { + "id": "TC001", + "name": "用户登录-正常流程", + "source": "AC-001", + "type": "功能测试", + "priority": "P0", + "steps": [...], + "expected_result": "...", + "test_data": {...} + } + ] +} +``` + +--- + +### 第2步:读取需求文档 + +**目标**:解析需求文档,提取验收标准和功能点 + +**提取内容**: +```markdown +## 验收标准提取 + +### 格式模式 +- AC-xxx: 描述 + +### 示例 +- AC-001: 用户输入用户名和密码,点击登录,登录成功 +- AC-002: 用户输入错误的密码,登录失败,提示"密码错误" +- AC-003: 用户输入不存在的用户名,提示"用户不存在" + +## 功能点提取 + +### 识别规则 +1. 功能描述章节的核心功能 +2. 每个功能的子功能 +3. 隐含的功能需求 +``` + +--- + +### 第3步:执行验收标准覆盖检查 + +**检查逻辑**: + +```python +def check_acceptance_criteria_coverage(test_cases, requirements): + """检查验收标准覆盖率""" + # 1. 提取需求文档的所有验收标准 + acceptance_criteria = extract_acceptance_criteria(requirements) + + # 2. 提取测试用例的来源字段 + covered_ac = set() + for tc in test_cases: + if tc.get('source'): + # 提取来源中的AC编号 + ac_ids = extract_ac_ids(tc['source']) + covered_ac.update(ac_ids) + + # 3. 识别未覆盖的验收标准 + missing_ac = [] + for ac in acceptance_criteria: + if ac['id'] not in covered_ac: + missing_ac.append(ac) + + return { + 'total': len(acceptance_criteria), + 'covered': len(covered_ac), + 'missing': missing_ac, + 'coverage_rate': len(covered_ac) / len(acceptance_criteria) * 100 + } +``` + +**输出示例**: +```markdown +### 验收标准覆盖率 + +| 验收标准 | 状态 | 对应测试用例 | +|---------|:----:|-------------| +| AC-001 | ✅ 已覆盖 | TC001 | +| AC-002 | ✅ 已覆盖 | TC002 | +| AC-003 | ❌ 未覆盖 | - | + +**覆盖率**: 66.7% (2/3) + +**缺失的验收标准**: +- AC-003: 用户输入不存在的用户名,提示"用户不存在" +``` + +--- + +### 第4步:执行功能点完整性检查 + +**功能点提取算法**: + +```python +def extract_function_points(requirements): + """从需求文档提取功能点""" + function_points = [] + + # 1. 基于章节结构提取 + sections = parse_sections(requirements) + for section in sections: + if section['level'] == 2: ## 二级标题 + function_points.append({ + 'id': f"FP-{len(function_points)+1:03d}", + 'name': section['title'], + 'description': section['content'] + }) + + # 2. 基于关键词提取 + patterns = [ + r'支持(.*)功能', + r'可以(.*)', + r'提供(.*)', + r'实现(.*)' + ] + for pattern in patterns: + matches = re.findall(pattern, requirements) + for match in matches: + function_points.append({ + 'id': f"FP-{len(function_points)+1:03d}", + 'name': match, + 'description': '' + }) + + return function_points +``` + +--- + +### 第5步:执行边界场景检查 + +**边界场景检测算法**: + +```python +def check_boundary_scenarios(test_cases, domain): + """检查边界场景""" + boundary_types = { + '空值': r'["\[\]\{\}]|空|empty', + 'null值': r'null|None', + '零值': r'\b0\b', + '极值': r'MAX_VALUE|MIN_VALUE|最大|最小', + '长度边界': r'长度.*最大|长度.*最小|max.*length|min.*length' + } + + covered = {bt: False for bt in boundary_types} + + for tc in test_cases: + test_data = str(tc.get('test_data', '')) + str(tc.get('steps', '')) + for bt, pattern in boundary_types.items(): + if re.search(pattern, test_data, re.IGNORECASE): + covered[bt] = True + + missing = [bt for bt, is_covered in covered.items() if not is_covered] + + return { + 'total': len(boundary_types), + 'covered': sum(covered.values()), + 'missing': missing, + 'coverage_rate': sum(covered.values()) / len(boundary_types) * 100 + } +``` + +--- + +### 第6步:执行异常场景检查 + +**异常场景检测算法**: + +```python +def check_exception_scenarios(test_cases, requirements): + """检查异常场景""" + exception_types = { + '参数校验异常': ['校验', '验证', '格式', '必填'], + '权限异常': ['权限', '未授权', '无权限'], + '资源不存在': ['不存在', '未找到'], + '并发冲突': ['并发', '冲突'], + '超时异常': ['超时', 'timeout'], + '业务规则异常': ['余额', '库存', '限制'] + } + + # 从需求文档识别需要的异常类型 + required_exceptions = [] + for exc_type, keywords in exception_types.items(): + for keyword in keywords: + if keyword in requirements: + required_exceptions.append(exc_type) + break + + # 检查测试用例是否覆盖 + covered = set() + for tc in test_cases: + for exc_type in required_exceptions: + if exc_type in tc['name'] or exc_type in str(tc.get('steps', '')): + covered.add(exc_type) + + missing = [et for et in required_exceptions if et not in covered] + + return { + 'total': len(required_exceptions), + 'covered': len(covered), + 'missing': missing, + 'coverage_rate': len(covered) / len(required_exceptions) * 100 if required_exceptions else 100 + } +``` + +--- + +### 第7步:执行冗余检查 + +**冗余检测算法**: + +```python +def check_redundancy(test_cases): + """检查冗余测试用例""" + redundant = [] + + for i, tc1 in enumerate(test_cases): + for j, tc2 in enumerate(test_cases[i+1:], i+1): + # 计算相似度 + similarity = calculate_similarity(tc1, tc2) + + if similarity >= 0.9: + redundant.append({ + 'type': '完全重复' if similarity == 1.0 else '高度相似', + 'tc1': tc1['id'], + 'tc2': tc2['id'], + 'similarity': similarity + }) + + return { + 'total': len(test_cases), + 'redundant_count': len(redundant), + 'redundant_list': redundant + } + +def calculate_similarity(tc1, tc2): + """计算两个测试用例的相似度""" + # 1. 步骤相似度 + steps1 = ' '.join(tc1.get('steps', [])) + steps2 = ' '.join(tc2.get('steps', [])) + steps_sim = string_similarity(steps1, steps2) + + # 2. 测试数据相似度 + data1 = str(tc1.get('test_data', {})) + data2 = str(tc2.get('test_data', {})) + data_sim = string_similarity(data1, data2) + + # 综合相似度 + return (steps_sim * 0.7 + data_sim * 0.3) +``` + +--- + +### 第8步:计算质量评分 + +```python +def calculate_score(issues): + """计算质量评分""" + score = 100 + + # 统计各级问题数量 + p0_ac_missing = sum(1 for i in issues if i['severity'] == 'P0' and i['type'] == '验收标准缺失') + p0_fp_missing = sum(1 for i in issues if i['severity'] == 'P0' and i['type'] == '功能点缺失') + p1_boundary = sum(1 for i in issues if i['severity'] == 'P1' and i['type'] == '边界场景缺失') + p1_exception = sum(1 for i in issues if i['severity'] == 'P1' and i['type'] == '异常场景缺失') + p2_redundant = sum(1 for i in issues if i['severity'] == 'P2' and i['type'] == '冗余') + + # 计算扣分 + score -= p0_ac_missing * 20 + score -= p0_fp_missing * 15 + score -= p1_boundary * 10 + score -= p1_exception * 10 + score -= p2_redundant * 5 + + # 确保分数不低于0 + score = max(0, score) + + # 确定等级 + if p0_ac_missing > 0 or p0_fp_missing > 0: + grade = 'F' + elif p1_boundary + p1_exception >= 3: + grade = min('C', grade_from_score(score)) + else: + grade = grade_from_score(score) + + return score, grade +``` + +--- + +### 第9步:生成优化建议 + +**建议生成逻辑**: + +```python +def generate_optimization_suggestions(issues, test_cases): + """生成优化建议""" + suggestions = { + 'add': [], # 新增测试用例 + 'modify': [], # 修改现有测试用例 + 'delete': [] # 删除冗余测试用例 + } + + for issue in issues: + if issue['type'] == '验收标准缺失': + suggestions['add'].append({ + 'type': '补充验收标准测试', + 'target': issue['target'], + 'priority': 'P0', + 'suggestion': f"针对验收标准「{issue['target']}」新增测试用例" + }) + + elif issue['type'] == '边界场景缺失': + suggestions['add'].append({ + 'type': '补充边界测试', + 'boundary_type': issue['boundary_type'], + 'priority': 'P1', + 'suggestion': f"新增{issue['boundary_type']}边界测试用例" + }) + + elif issue['type'] == '冗余': + suggestions['delete'].append({ + 'type': '删除冗余用例', + 'tc1': issue['tc1'], + 'tc2': issue['tc2'], + 'suggestion': f"删除{issue['tc2']},保留{issue['tc1']}" + }) + + return suggestions +``` + +--- + +### 第10步:生成Review报告 + +**报告模板**: + +```markdown +# {功能名} 测试用例文档Review报告 + +**生成时间**: {YYYY-MM-DD HH:mm:ss} +**检查范围**: 测试用例文档 + 需求文档 +**评分**: {score}/100 ({grade}) + +--- + +## 执行摘要 + +| 统计项 | 数量 | +|-------|-----:| +| 📁 检查文档数 | 2 | +| 📋 测试用例总数 | {total_tc} | +| ✅ 通过检查项 | {pass_count} | +| ⚠️ 发现问题 | {issue_count} | +| 📝 优化建议 | {suggestion_count} | + +**总体状态**: {status} + +--- + +## 问题详情 + +### 🔴 P0级问题(阻断) + +{验收标准缺失、功能点缺失} + +### 🟠 P1级问题(警告) + +{边界场景缺失、异常场景缺失} + +### 🟡 P2级问题(提示) + +{冗余用例} + +--- + +## 覆盖率分析 + +### 验收标准覆盖率 + +| 验收标准 | 状态 | 对应测试用例 | +|---------|:----:|-------------| +| AC-001 | ✅ | TC001 | +| AC-002 | ❌ | - | + +**覆盖率**: {rate}% ({covered}/{total}) + +### 功能点覆盖率 + +| 功能点 | 状态 | 测试用例数 | +|-------|:----:|----------:| +| 用户登录 | ✅ | 3 | +| 密码找回 | ❌ | 0 | + +**覆盖率**: {rate}% ({covered}/{total}) + +--- + +## 优化建议 + +### 新增测试用例 + +| 优先级 | 类型 | 说明 | +|-------|-----:|------| +| P0 | 验收标准缺失 | 补充AC-003测试用例 | +| P1 | 边界场景 | 新增空字符串测试 | + +### 修改测试用例 + +| 测试用例 | 修改项 | 说明 | +|---------|-------|------| +| TC005 | 测试数据 | 补充边界值 | + +### 删除冗余用例 + +| 测试用例 | 冗余原因 | 保留用例 | +|---------|---------|---------| +| TC010 | 与TC003高度相似 | TC003 | + +--- + +## 质量评分详情 + +{评分明细表} + +--- + +## 附录 + +### A. 测试用例清单 + +{所有测试用例列表} + +### B. 需求文档摘要 + +{需求文档的关键信息} + +### C. 修复检查清单 + +- [ ] 所有P0级问题已修复 +- [ ] 所有P1级问题已修复 +- [ ] 重新运行Review验证 +``` + +--- + +## 与functional-test-generator的集成 + +当`functional-test-generator`完成测试用例文档生成后,自动调用`test-case-document-reviewer`: + +``` +functional-test-generator输出: + "✅ 测试用例文档已生成: docs/dev/testing/xxx_测试用例.md" + + ↓ 自动触发 ↓ + +test-case-document-reviewer执行: + "🔍 开始测试用例文档Review..." + "📊 Review报告已生成: docs/dev/testing/xxx_测试用例文档Review.md" +``` + +**为什么要Review测试用例文档?** + +| 问题 | 风险 | Review作用 | +|-----|------|----------| +| 验收标准未覆盖 | 需求未被测试,质量风险 | 识别并报告缺失 | +| 缺少边界测试 | 边界条件下的缺陷 | 提示补充边界用例 | +| 缺少异常测试 | 异常处理不完善 | 提示补充异常用例 | +| 冗余用例 | 测试效率低 | 建议删除或合并 | + +--- + +## 质量标准 + +Review过程必须满足: + +- ✅ 100%识别验收标准缺失(无漏报) +- ✅ 准确识别功能点覆盖情况 +- ✅ 全面检查边界和异常场景 +- ✅ 提供可执行的优化建议 +- ✅ 评分准确反映文档质量 + +--- + +## 输出示例 + +Review完成后,应该输出: + +```markdown +🔍 测试用例文档Review完成 + +📊 Review统计: +- 检查文档: 2个(测试用例 + 需求) +- 测试用例: 15个 +- 发现问题: 3个 + - 🔴 P0级: 1个(验收标准缺失) + - 🟠 P1级: 2个(边界场景缺失) + +📈 质量评分: 85/100 (B) - 良好 + +📄 Review报告已生成: docs/dev/testing/xxx_测试用例文档Review.md + +💡 下一步: +1. 查看Review报告详情 +2. 根据优化建议补充测试用例 +3. 重新运行Review验证 +``` + +--- + +## 注意事项 + +1. **不修改测试用例文档** - Review只检查,不修改 +2. **建议优先修复P0** - P0级问题会阻断需求覆盖 +3. **重新Review验证** - 修复后建议重新运行Review确认 +4. **结合业务判断** - 某些场景可能不适用,需人工判断 diff --git a/.claude/skills/test-code-reviewer/SKILL.md b/.claude/skills/test-code-reviewer/SKILL.md new file mode 100644 index 0000000000000000000000000000000000000000..40153b26c4cb54e6632dfc2968dde093fd5f66fc --- /dev/null +++ b/.claude/skills/test-code-reviewer/SKILL.md @@ -0,0 +1,701 @@ +--- +name: test-code-reviewer +type: testing +description: 自动化测试代码完整性检查专家,识别空实现、假阳性断言、测试覆盖问题 +version: 1.1 +author: DevSyncAgent Team +last_updated: 2026-02-08 +changelog: + v1.1 - 2026-02-08 + - 🆕 新增子需求模式检测与处理 + - 🔄 支持DevOps自动循环中子需求测试代码审查 + - 🔄 子需求模式:基于父需求测试代码审查修改内容 + - 🔄 从cycle-state.json读取parentRequirementId + - 🔄 审查策略差异化:子需求模式检查修改内容质量 + - 🔄 提供@Tag("sub-requirement")标记建议 + v1.0 - 2026-02-02 + - 初始版本 + - 支持Java/Python测试代码检查 + - 空实现检测 + - 假阳性断言检测 + - 测试覆盖率检查 + - 质量评分机制 +--- + +# 测试代码Review Skill + +你是测试代码完整性检查专家,负责审查自动化测试代码的质量,识别空实现、假阳性断言、测试覆盖等问题。 + +## 适用场景 + +- 在 `automated-test-executor` 执行后自动检查测试代码质量 +- 对现有测试代码进行完整性审查 +- 识别空实现、假阳性、无断言等低质量测试 +- 验证测试覆盖率与Feature文件的一致性 + +## 核心能力 + +| 能力 | 说明 | +|-----|------| +| **空实现检测** | 识别测试方法体为空或只有TODO注释 | +| **假阳性断言检测** | 识别`assertTrue(true)`等无意义断言 | +| **无断言检测** | 识别测试方法内缺少任何断言 | +| **测试覆盖检查** | 验证Feature Scenario是否有对应测试 | +| **质量评分** | 基于问题严重程度计算评分(A-F等级) | + +## 输入 + +**优先级顺序**: + +1. **测试代码文件**(必须): + - Java: `src/test/java/**/*.java` + - Python: `src/test/**/*.py`, `tests/**/*.py` +2. **Feature文件**(可选): + - 路径:`dev/active/{task-name}/features/*.feature` + - 用途:测试覆盖率检查 +3. **测试用例文档**(可选): + - 路径:`docs/{branch}/testing/{功能名}_测试用例.md` + +## 输出 + +**主要输出**: +- 📊 **测试代码Review报告**(Markdown格式) + +**输出路径**: +``` +docs/{branch}/testing/ +└── {功能名}_代码Review.md +``` + +## 检查规则 + +### 规则1: 空实现检测(P0) + +检测测试方法/函数体是否为空或仅包含占位符。 + +| 语言 | 检测模式 | 示例 | 严重程度 | +|-----|---------|------|:-------:| +| Java | `\{\s*(//.*|\*)*\}` | `void test() {}` | 🔴 P0 | +| Java | `TODO.*not.*implement` | `// TODO: implement` | 🔴 P0 | +| Java | `NotImplementedException` | `throw new NotImplementedException` | 🔴 P0 | +| Python | `def.*:\s*(pass|#.*TODO)` | `def test(): pass` | 🔴 P0 | +| Python | `raise NotImplementedError` | `raise NotImplementedError` | 🔴 P0 | + +**扣分**:-20分/个 + +--- + +### 规则2: 假阳性断言检测(P0) + +识别永远通过或永远失败的无意义断言。 + +| 断言类型 | Java模式 | Python模式 | 示例 | 严重程度 | +|---------|---------|-----------|------|:-------:| +| 恒真断言 | `assertTrue\(true\)` | `assert True` | `assertTrue(true)` | 🔴 P0 | +| 恒假断言 | `assertFalse\(false\)` | `assert False` | `assertFalse(false)` | 🔴 P0 | +| 空对象断言 | `assertNotNull\(new` | `assert x is not None` | `assertNotNull(new Object())` | 🔴 P0 | +| 相同比较 | `assertEquals\(x,\s*x\)` | `assert x == x` | `assertEquals(a, a)` | 🔴 P0 | + +**扣分**:-15分/个 + +--- + +### 规则3: 无断言检测(P1) + +检测测试方法内是否包含任何有效的断言语句。 + +| 语言 | 断言模式 | 说明 | 严重程度 | +|-----|---------|------|:-------:| +| Java | `assert.*\(` | JUnit/AssertJ断言 | 🟠 P1 | +| Python | `assert .+` | Python断言 | 🟠 P1 | + +**例外情况**: +- 方法包含`throw`或`raises`(预期异常测试) +- 方法包含`wait`或`sleep`(等待类测试) + +**扣分**:-10分/个 + +--- + +### 规则4: 测试覆盖检查(P1) + +验证Feature文件中的Scenario是否都有对应的测试实现。 + +| 检查项 | 说明 | 严重程度 | +|-------|------|:-------:| +| Scenario覆盖率 | 每个Scenario是否有Step Definition | 🟠 P1 | +| 测试用例覆盖率 | 每个测试用例是否有对应测试方法 | 🟠 P1 | + +**扣分**:-5分/个缺失 + +--- + +## 质量评分 + +### 评分规则 + +**初始分**:100分 + +| 扣分项 | 分值 | 等级 | +|-------|-----:|:----:| +| 空实现 | -20分/个 | P0 | +| 假阳性断言 | -15分/个 | P0 | +| 无断言 | -10分/个 | P1 | +| 覆盖缺失 | -5分/个 | P1 | + +**最终等级**: + +| 分数区间 | 等级 | 含义 | 报告状态 | +|---------|-----|------|:--------:| +| 90-100 | A | 优秀 | ✅ 通过 | +| 80-89 | B | 良好 | ✅ 通过 | +| 70-79 | C | 及格 | ⚠️ 警告 | +| 60-69 | D | 需改进 | ⚠️ 警告 | +| <60 | F | 阻断 | ❌ 阻断 | + +**特殊规则**: +- 存在**任何P0级问题** → 自动降为F级(阻断) +- 存在**3个及以上P1级问题** → 最高不超过C级 + +--- + +## 子需求模式检测 🆕v1.1 + +**目标**:检测当前测试代码是否为DevOps循环中子需求的修改代码 + +### 检测逻辑 + +```markdown +1. 检查 cycle-state.json 是否存在 + IF 存在 THEN + 读取 parentRequirementId 和 subRequirementType + + IF subRequirementType == "bug-fix" THEN + 进入【子需求审查模式】 + ELSE + 进入【标准审查模式】 + END IF +ELSE + 进入【标准审查模式】 +END IF +``` + +### 子需求审查模式处理策略 + +当检测到子需求模式时: + +**1. 读取父需求测试代码** +```markdown +路径:src/test/java/**/*.java 或 src/test/**/*.py +``` + +**2. 审查策略差异** + +| 审查维度 | 标准模式 | 子需求模式 | +|---------|---------|-----------| +| 空实现检测 | 检查所有测试方法 | 仅检查新增/修改的方法 | +| 假阳性检测 | 检查所有断言 | 仅检查新增/修改的断言 | +| 覆盖率检查 | 检查Feature覆盖率 | 检查修改内容的覆盖 | +| 评分标准 | 完整代码评分 | 修改内容评分 | + +**3. 输出调整** +- ✅ 报告中标识子需求模式 +- ✅ 说明基于父需求代码的修改内容 +- ✅ 提供@Tag("sub-requirement")标记建议 + +**4. 子需求模式提示** +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔄 **子需求审查模式**(DevOps自动循环) + +检测到当前测试代码为子需求修改代码: +- 父需求ID: {parentRequirementId} +- 审查策略: 基于父需求测试代码审查修改内容 + +📋 **审查重点**: +- ✅ 新增测试方法是否覆盖失败场景 +- ✅ 修改的测试方法是否保持一致性 +- ✅ 是否标记@Tag("sub-requirement") + +> 📌 父需求测试代码:{父需求测试代码路径} +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + +## Review流程 + +```mermaid +graph TD + A[开始] --> B[第1步: 扫描测试代码文件] + B --> C[第2步: 解析测试方法/函数] + C --> D[第3步: 执行空实现检测] + D --> E[第4步: 执行假阳性断言检测] + E --> F[第5步: 执行无断言检测] + F --> G{有Feature文件?} + G -->|是| H[第6步: 执行测试覆盖检查] + G -->|否| I[跳过覆盖检查] + H --> I + I --> J[第7步: 计算质量评分] + J --> K[第8步: 生成Review报告] + K --> L{有P0问题?} + L -->|是| M[报告状态: 阻断] + L -->|否| N[报告状态: 通过/警告] + M --> O[结束] + N --> O +``` + +--- + +## 详细步骤 + +### 第1步:扫描测试代码文件 + +**目标**:识别所有需要检查的测试文件 + +```bash +# 扫描Java测试文件 +find src/test/java -name "*Test.java" -o -name "*Steps.java" + +# 扫描Python测试文件 +find src/test tests -name "test_*.py" -o -name "*_test.py" +``` + +**输出格式**: +```markdown +## 扫描结果 + +| 语言 | 文件数 | 文件列表 | +|-----|------:|---------| +| Java | 3 | BubbleSortSteps.java, BubbleSortServiceTest.java, ... | +| Python | 2 | test_bubble_sort.py, test_steps.py | +``` + +--- + +### 第2步:解析测试方法/函数 + +**目标**:提取所有测试方法/函数的签名和内容 + +**Java解析示例**: +```java +@Test +@DisplayName("应该返回升序数组") +public void shouldReturnSortedArray() { + // 方法体内容 +} +``` + +**Python解析示例**: +```python +def test_should_return_sorted_array(): + # 函数体内容 + pass +``` + +--- + +### 第3步:执行空实现检测 + +**检测逻辑**: + +```python +def detect_empty_implementation(method_body, language): + """检测空实现""" + if language == "Java": + # 检查空花括号 + if re.search(r'\{\s*(//.*|\*)*\}', method_body): + return True, "方法体为空" + # 检查TODO注释 + if re.search(r'TODO.*not.*implement', method_body, re.IGNORECASE): + return True, "包含TODO未实现标记" + # 检查NotImplementedException + if "throw new NotImplementedException" in method_body: + return True, "抛出NotImplementedException" + + elif language == "Python": + # 检查pass + if re.search(r'def.*:\s*(pass|#.*TODO)', method_body): + return True, "方法体仅为pass或TODO" + # 检查NotImplementedError + if "raise NotImplementedError" in method_body: + return True, "抛出NotImplementedError" + + return False, None +``` + +--- + +### 第4步:执行假阳性断言检测 + +**检测逻辑**: + +```python +def detect_false_positive_assertions(method_body, language): + """检测假阳性断言""" + issues = [] + + if language == "Java": + # 恒真断言 + if re.search(r'assertTrue\s*\(\s*true\s*\)', method_body): + issues.append("assertTrue(true)") + # 恒假断言 + if re.search(r'assertFalse\s*\(\s*false\s*\)', method_body): + issues.append("assertFalse(false)") + # 空对象断言 + if re.search(r'assertNotNull\s*\(\s*new\s+', method_body): + issues.append("assertNotNull(new ...)") + # 相同比较 + if re.search(r'assertEquals\s*\(\s*\w+\s*,\s*\1\s*\)', method_body): + issues.append("assertEquals(x, x)") + + elif language == "Python": + # 恒真断言 + if re.search(r'assert\s+True\s*$', method_body, re.MULTILINE): + issues.append("assert True") + # 恒假断言 + if re.search(r'assert\s+False\s*$', method_body, re.MULTILINE): + issues.append("assert False") + # 相同比较 + if re.search(r'assert\s+\w+\s*==\s*\1\s*$', method_body, re.MULTILINE): + issues.append("assert x == x") + + return issues +``` + +--- + +### 第5步:执行无断言检测 + +**检测逻辑**: + +```python +def detect_missing_assertions(method_body, language): + """检测无断言""" + if language == "Java": + # 检查是否包含断言 + has_assertion = re.search(r'assert.*\(', method_body) + # 检查是否是异常测试 + is_exception_test = re.search(r'(assertThrows|expectThrows)', method_body) + + if not has_assertion and not is_exception_test: + return True, "缺少断言语句" + + elif language == "Python": + # 检查是否包含断言 + has_assertion = re.search(r'^assert\s+.+', method_body, re.MULTILINE) + # 检查是否是异常测试 + is_exception_test = re.search(r'(raises|with_raises)', method_body) + + if not has_assertion and not is_exception_test: + return True, "缺少断言语句" + + return False, None +``` + +--- + +### 第6步:执行测试覆盖检查 + +**检测逻辑**: + +```python +def check_test_coverage(scenarios, step_definitions, test_cases, test_methods): + """检查测试覆盖率""" + coverage_issues = [] + + # 检查Scenario覆盖率 + for scenario in scenarios: + scenario_name = scenario['name'] + # 尝试匹配Step Definition + matched = any(scenario_name.lower() in sd.lower() for sd in step_definitions) + if not matched: + coverage_issues.append({ + 'type': 'Scenario缺失', + 'name': scenario_name, + 'severity': 'P1' + }) + + # 检查测试用例覆盖率 + for test_case in test_cases: + test_case_id = test_case['id'] + matched = any(test_case_id in tm for tm in test_methods) + if not matched: + coverage_issues.append({ + 'type': '测试用例缺失', + 'name': test_case_id, + 'severity': 'P1' + }) + + return coverage_issues +``` + +--- + +### 第7步:计算质量评分 + +```python +def calculate_score(issues): + """计算质量评分""" + score = 100 + + # 统计各级问题数量 + p0_empty = sum(1 for i in issues if i['severity'] == 'P0' and i['type'] == '空实现') + p0_false = sum(1 for i in issues if i['severity'] == 'P0' and i['type'] == '假阳性断言') + p1_no_assert = sum(1 for i in issues if i['severity'] == 'P1' and i['type'] == '无断言') + p1_coverage = sum(1 for i in issues if i['severity'] == 'P1' and i['type'] == '覆盖缺失') + + # 计算扣分 + score -= p0_empty * 20 + score -= p0_false * 15 + score -= p1_no_assert * 10 + score -= p1_coverage * 5 + + # 确保分数不低于0 + score = max(0, score) + + # 确定等级 + if p0_empty > 0 or p0_false > 0: + grade = 'F' + elif p1_no_assert + p1_coverage >= 3: + grade = min('C', grade_from_score(score)) + else: + grade = grade_from_score(score) + + return score, grade + +def grade_from_score(score): + """根据分数确定等级""" + if score >= 90: + return 'A' + elif score >= 80: + return 'B' + elif score >= 70: + return 'C' + elif score >= 60: + return 'D' + else: + return 'F' +``` + +--- + +### 第8步:生成Review报告 + +**报告模板**: + +```markdown +# {功能名} 测试代码Review报告 + +**生成时间**: {YYYY-MM-DD HH:mm:ss} +**检查范围**: {N}个测试文件 +**评分**: {score}/100 ({grade}) + +--- + +## 执行摘要 + +| 统计项 | 数量 | +|-------|-----:| +| 📁 扫描文件数 | {total_files} | +| 🔍 检查方法数 | {total_methods} | +| ✅ 通过 | {pass_count} | +| ⚠️ 警告 | {warning_count} | +| ❌ 阻断 | {block_count} | + +**总体状态**: {status} + +--- + +## 问题详情 + +### 🔴 P0级问题(阻断) + +{如果有P0问题,列出详情} + +#### {问题ID}: {问题类型} - {方法名} + +**位置**: `{文件名}:{行号}` + +**严重程度**: 🔴 P0(阻断) + +**代码片段**: +```java/python +{问题代码} +``` + +**问题描述**: +{详细说明} + +**修复建议**: +```java/python +{修复后的代码} +``` + +--- + +### 🟠 P1级问题(警告) + +{如果有P1问题,列出详情} + +#### {问题ID}: {问题类型} - {方法名} + +**位置**: `{文件名}:{行号}` + +**严重程度**: 🟠 P1(警告) + +**代码片段**: +```java/python +{问题代码} +``` + +**问题描述**: +{详细说明} + +**修复建议**: +```java/python +{修复后的代码} +``` + +--- + +## 覆盖率分析 + +### Feature Scenario覆盖率 + +| Feature | Scenario总数 | 已覆盖 | 覆盖率 | 缺失 | +|---------|------------:|------:|------:|------| +| {feature1}.feature | {total} | {covered} | {rate}% | {missing} | + +### 覆盖详情 + +{列出未覆盖的Scenario} + +--- + +## 质量评分详情 + +| 评分项 | 得分 | 满分 | 扣分原因 | +|-------|-----:|-----:|---------| +| 初始分 | - | 100 | - | +| 空实现扣分 | -{deduct} | - | {count}个空实现 | +| 假阳性断言扣分 | -{deduct} | - | {count}个假阳性 | +| 无断言扣分 | -{deduct} | - | {count}个无断言 | +| 覆盖缺失扣分 | -{deduct} | - | {count}个覆盖缺失 | +| **最终得分** | **{score}** | **100** | - | +| **等级** | **{grade}** | - | - | + +--- + +## 建议修复顺序 + +1. 🔴 **优先修复P0级问题**({count}个)- 阻塞测试执行 +2. 🟠 **其次修复P1级问题**({count}个)- 影响测试有效性 +3. 🟡 **最后优化P2级问题**({count}个)- 提升测试质量 + +--- + +## 总体建议 + +{基于分析结果的整体建议} + +--- + +## 附录 + +### A. 检查规则说明 + +| 规则ID | 规则名称 | 严重程度 | 扣分 | +|-------|---------|:-------:|-----:| +| RULE_001 | 空实现检测 | P0 | -20 | +| RULE_002 | 假阳性断言检测 | P0 | -15 | +| RULE_003 | 无断言检测 | P1 | -10 | +| RULE_004 | 测试覆盖检查 | P1 | -5 | + +### B. 文件清单 + +{列出所有检查的文件} + +### C. 修复检查清单 + +- [ ] 所有P0级问题已修复 +- [ ] 所有P1级问题已修复 +- [ ] 重新运行Review验证 +- [ ] 测试执行通过 +``` + +--- + +## 与automated-test-executor的集成 + +当`automated-test-executor`完成测试执行后,自动调用`test-code-reviewer`: + +``` +automated-test-executor输出: + "✅ 测试执行完成" + "📄 验证结果已生成: docs/dev/testing/bubble-sort_自动化测试验证结果.md" + + ↓ 自动触发 ↓ + +test-code-reviewer执行: + "🔍 开始测试代码Review..." + "📊 Review报告已生成: docs/dev/testing/bubble-sort_代码Review.md" +``` + +**为什么要Review?** + +| 问题 | 风险 | Review作用 | +|-----|------|----------| +| 空实现 | 测试未真实验证,但显示"通过" | 识别并标记为阻断 | +| 假阳性断言 | 测试永远通过,无法发现缺陷 | 识别并报告问题 | +| 无断言 | 测试执行但无验证 | 提示添加断言 | +| 覆盖缺失 | 部分场景未测试 | 报告缺失的测试 | + +--- + +## 质量标准 + +Review过程必须满足: + +- ✅ 检测100%的空实现(无漏报) +- ✅ 检测100%的假阳性断言(无漏报) +- ✅ 准确识别测试覆盖率(与Feature文件对比) +- ✅ 提供可执行的修复建议(含代码示例) +- ✅ 评分准确反映测试代码质量 + +--- + +## 输出示例 + +Review完成后,应该输出: + +```markdown +🔍 测试代码Review完成 + +📊 Review统计: +- 扫描文件: 3个 +- 检查方法: 15个 +- 发现问题: 5个 + - 🔴 P0级: 2个(空实现: 1, 假阳性: 1) + - 🟠 P1级: 3个(无断言: 2, 覆盖缺失: 1) + +📈 质量评分: 65/100 (D) - 需改进 + +📄 Review报告已生成: docs/dev/testing/bubble-sort_代码Review.md + +⚠️ 检测到P0级问题,建议修复后重新执行测试 + +💡 下一步: +1. 查看Review报告详情 +2. 按优先级修复问题 +3. 重新执行测试验证 +``` + +--- + +## 注意事项 + +1. **不修改测试代码** - Review只检查,不修改 +2. **不执行测试** - Review是静态分析,不运行测试 +3. **建议优先修复P0** - P0级问题会阻断测试有效性 +4. **重新Review验证** - 修复后建议重新运行Review确认 diff --git a/.claude/skills/test-report/SKILL.md b/.claude/skills/test-report/SKILL.md index 1f474a6d08aa2ca4e06a44b1a2f1cd8aa1449f47..bc8003bf038549ea6671fb556e3c93d9106514da 100644 --- a/.claude/skills/test-report/SKILL.md +++ b/.claude/skills/test-report/SKILL.md @@ -1,10 +1,23 @@ --- name: test-report description: 测试报告生成Skill,根据需求文档、缺陷文件、测试用例和测试执行报告生成详细的最终测试报告 -version: 3.5 +version: 3.7 author: DevSyncAgent Team -last_updated: 2026-01-29 +last_updated: 2026-02-08 changelog: + v3.7 - 2026-02-08 + - 🆕 新增子需求模式检测与处理 + - 🔄 支持DevOps自动循环中子需求测试报告生成 + - 🔄 子需求模式:基于父需求测试数据生成修复验证报告 + - 🔄 从cycle-state.json读取parentRequirementId + - 🔄 对比父需求测试结果,展示修复效果 + - 🔄 循环决策基于bug修复验证结果 + v3.6 - 2026-02-02 + - 🆕 DevOps自动循环支持:新增循环决策输出 + - 🆕 新增"下一步行动"章节,明确是否需要继续循环修复bug + - 🆕 支持读取test-status.json获取循环信息 + - 🆕 根据测试通过率和缺陷数量自动决策是否继续循环 + - 🆕 输出未通过测试用例清单,供代码修复阶段使用 v3.5 - 2026-01-29 - 新增必填目录空值检查,目录为空时中断并提示用户 - 修改输出路径格式为时间戳目录(reports/test-report-YYYYMMDDHHMMSS/) @@ -29,6 +42,7 @@ changelog: 2. **智能缺陷关联**:根据测试用例属性(前端/后端/数据)自动关联缺陷 3. **统计分析**:自动计算测试覆盖率、通过率、缺陷分布 4. **报告生成**:生成结构化的测试报告文档 +5. **DevOps循环决策** 🆕:根据测试结果自动判断是否需要继续循环修复bug ## 输入参数 @@ -50,6 +64,74 @@ changelog: **注意**:输出路径将自动生成为 `{output_dir}/test-report-{timestamp}/`,其中timestamp格式为YYYYMMDDHHMMSS +## 子需求模式检测 🆕v3.7 + +**目标**:检测当前测试报告是否为DevOps循环中子需求的测试报告 + +### 检测逻辑 + +```markdown +1. 检查 cycle-state.json 是否存在 + IF 存在 THEN + 读取 parentRequirementId 和 subRequirementType + + IF subRequirementType == "bug-fix" THEN + 进入【子需求报告模式】 + ELSE + 进入【标准报告模式】 + END IF +ELSE + 进入【标准报告模式】 +END IF +``` + +### 子需求报告模式处理策略 + +当检测到子需求模式时: + +**1. 读取父需求测试数据** +```markdown +- 父需求测试用例文档 +- 父需求测试执行报告 +- 父需求测试报告(如果有) +``` + +**2. 报告生成策略差异** + +| 报告维度 | 标准模式 | 子需求模式 | +|---------|---------|-----------| +| 测试数据 | 完整测试数据 | 仅包含修改的测试数据 | +| 统计分析 | 完整统计分析 | 基于修改内容的对比分析 | +| 缺陷关联 | 关联所有缺陷 | 仅关联本次修复的缺陷 | +| 循环决策 | 决定是否继续循环 | 决定是否继续循环(修复验证) | + +**3. 报告内容调整** +- ✅ 报告标题标识子需求模式 +- ✅ 说明这是基于父需求的bug fix验证报告 +- ✅ 对比父需求测试结果,展示修复效果 +- ✅ 循环决策基于修复验证结果 + +**4. 子需求报告提示** +```markdown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔄 **子需求报告模式**(DevOps自动循环) + +检测到当前为子需求测试报告: +- 父需求ID: {parentRequirementId} +- 报告策略: 基于父需求测试数据生成修复验证报告 + +📋 **报告重点**: +- ✅ 对比父需求测试结果 +- ✅ 展示失败场景修复效果 +- ✅ 验证bug是否已修复 +- ✅ 决策是否继续循环 + +> 📌 父需求测试数据:{父需求测试数据路径} +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + ## 执行流程 ### 阶段1:参数收集与验证 @@ -166,6 +248,155 @@ changelog: 4. 提供完整报告路径 ``` +### 阶段6:DevOps循环决策 🆕 + +**目标**:根据测试结果判断是否需要继续 DevOps 循环修复 bug。 + +#### 决策逻辑 + +```bash +# 读取测试状态文件(如果存在) +STATUS_FILE="dev/active/{task-name}/test-status.json" + +if [ -f "$STATUS_FILE" ]; then + CYCLE_COUNT=$(jq -r '.cycleCount // 1' $STATUS_FILE) +else + CYCLE_COUNT=1 +fi + +# 决策条件 +TOTAL_CASES=统计总测试用例数 +PASSED_CASES=统计通过用例数 +FAILED_CASES=统计失败用例数 +DEFECT_COUNT=统计缺陷数量 + +# 计算通过率 +PASS_RATE=$(awk "BEGIN {printf \"%.2f\", ($PASSED_CASES/$TOTAL_CASES)*100}") + +# 决策规则 +if [ "$FAILED_CASES" -eq 0 ] && [ "$DEFECT_COUNT" -eq 0 ]; then + # 所有测试通过,无缺陷 + DECISION="EXIT" + REASON="所有测试通过,无缺陷发现" +elif [ "$PASS_RATE" -ge 95 ] && [ "$DEFECT_COUNT" -eq 0 ]; then + # 通过率≥95%,无缺陷 + DECISION="EXIT" + REASON="测试通过率${PASS_RATE}%,无缺陷发现" +else + # 存在失败用例或缺陷 + DECISION="CONTINUE" + REASON="存在${FAILED_CASES}个失败用例,${DEFECT_COUNT}个缺陷" +fi +``` + +#### 决策输出 + +**在报告末尾添加"下一步行动"章节**: + +```markdown +## 7. 下一步行动 🆕 + +### 7.1 循环决策 + +| 决策项 | 结果 | +|-------|------| +| 当前循环次数 | ${CYCLE_COUNT} | +| 总测试用例数 | ${TOTAL_CASES} | +| 通过用例数 | ${PASSED_CASES} | +| 失败用例数 | ${FAILED_CASES} | +| 测试通过率 | ${PASS_RATE}% | +| 缺陷数量 | ${DEFECT_COUNT} | +| **决策** | **${DECISION}** | + +### 7.2 决策说明 + +**决策结果**:${DECISION} + +**决策原因**:${REASON} + +#### 决策:EXIT(结束循环)✅ + +``` +======================================== +✅ DevOps 循环完成 +======================================== + +所有测试通过,质量达标。 + +📌 后续操作: +1. 代码已准备就绪,可以合并到主分支 +2. 生成最终测试报告:${REPORT_PATH} +3. 通知团队测试完成 + +======================================== +``` + +#### 决策:CONTINUE(继续循环)🔄 + +``` +======================================== +🔄 DevOps 循环继续 +======================================== + +发现 ${FAILED_CASES} 个失败用例 +发现 ${DEFECT_COUNT} 个缺陷 + +📌 未通过测试用例清单: + +| 序号 | 用例编号 | 用例名称 | 失败原因 | +|:----:|---------|---------|---------| +${FAILED_CASES_LIST} + +📌 后续操作: +1. 分析失败用例和缺陷 +2. 返回代码开发阶段修复问题 +3. 重新编译、部署、测试 +4. 下一次循环:#$((${CYCLE_COUNT} + 1)) + +======================================== +``` + +### 7.3 循环状态更新 + +```bash +# 更新循环状态文件 +CYCLE_STATE_FILE="dev/active/{task-name}/cycle-state.json" + +cat > $CYCLE_STATE_FILE << EOF +{ + "currentCycle": ${CYCLE_COUNT}, + "decision": "${DECISION}", + "reason": "${REASON}", + "failedCases": ${FAILED_CASES}, + "defectCount": ${DEFECT_COUNT}, + "passRate": ${PASS_RATE}, + "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", + "nextAction": "$([ "$DECISION" = "CONTINUE" ] && echo "代码修复" || echo "流程结束")" +} +EOF +``` + +#### DevOps 循环流程图 + +```mermaid +graph TD + A[测试报告生成] --> B{所有测试通过?} + B -->|是| C[决策: EXIT] + B -->|否| D{存在缺陷?} + D -->|是| E[决策: CONTINUE] + D -->|否| F{通过率 ≥ 95%?} + F -->|是| C + F -->|否| E + C --> G[流程结束] + E --> H[返回代码开发阶段] + H --> I[修复bug] + I --> J[重新编译] + J --> K[重新部署] + K --> L[健康检查] + L --> M[执行测试] + M --> A +``` + ## 测试用例属性识别规则 ### 前端测试用例 diff --git a/.mcp.json b/.mcp.json index 75a7be35b5ecf9d0386c9b8078d18996e3787d59..a474ba16490d9a60a5934347f88111fe580e1e9b 100644 --- a/.mcp.json +++ b/.mcp.json @@ -4,11 +4,27 @@ "type": "http", "transport": "streamable-http", "url": "http://tcftp.test.weoa.com/tctptestCommon/stream" + }, + "db-service": { + "command": "npx", + "args": ["-y", "@benborla29/mcp-server-mysql"], + "env": { + "MYSQL_HOST": "MYSQL_HOST", + "MYSQL_PORT": "3306", + "MYSQL_USER": "MYSQL_USER", + "MYSQL_PASS": "MYSQL_PASS", + "MYSQL_DB": "MYSQL_DB" + } + }, + "dpms": { + "type": "http", + "transport": "streamable-http", + "url": "http://tctpdevops.weoa.com/pros-admin-uat/sdpMcp/streamableHttp/dpms" + }, + "sdp": { + "type": "http", + "transport": "streamable-http", + "url": "http://tctpdevops.weoa.com/pros-admin-sit/sdpMcp/streamableHttp/sdpWorkflow" } - }, - "dpms": { - "url": "http://tctpdevops.weoa.com/pros-admin-uat/sdpMcp/streamableHttp/dpms", - "transport": "streamable-http", - "type": "http" } }