第一次提交
This commit is contained in:
221
agents/qa_agent.py
Normal file
221
agents/qa_agent.py
Normal file
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
QA Agent - 测试工程师智能体
|
||||
负责测试用例创建和 TDD 实践
|
||||
"""
|
||||
from autogen import AssistantAgent
|
||||
from typing import Dict, Any, Optional
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from config.llm_config import get_agent_llm_config, QA_PROMPT
|
||||
|
||||
|
||||
class QAAgent:
|
||||
"""测试工程师 Agent,负责生成测试用例和测试脚本"""
|
||||
|
||||
def __init__(self, llm_config: Optional[Dict] = None):
|
||||
"""
|
||||
初始化 QA Agent
|
||||
|
||||
Args:
|
||||
llm_config: LLM 配置
|
||||
"""
|
||||
self.llm_config = llm_config or get_agent_llm_config("QA_Agent")
|
||||
|
||||
self.agent = AssistantAgent(
|
||||
name="QA_Agent",
|
||||
system_message=QA_PROMPT,
|
||||
llm_config=self.llm_config,
|
||||
description="资深测试工程师,专注于自动化测试和 TDD 实践",
|
||||
human_input_mode="NEVER"
|
||||
)
|
||||
|
||||
self.workspace_dir = Path("workspace")
|
||||
self.workspace_dir.mkdir(exist_ok=True)
|
||||
|
||||
def generate_test_cases(self, srs_content: str) -> str:
|
||||
"""
|
||||
根据 SRS 生成测试用例
|
||||
|
||||
Args:
|
||||
srs_content: SRS 文档内容
|
||||
|
||||
Returns:
|
||||
生成的测试用例内容
|
||||
"""
|
||||
prompt = f"""
|
||||
请根据以下 SRS 文档生成完整的测试用例:
|
||||
|
||||
{self._truncate(srs_content, 3000)}
|
||||
|
||||
请生成:
|
||||
1. Pytest 测试脚本(包含完整的测试函数)
|
||||
2. BDD 风格的测试场景描述
|
||||
3. 测试数据准备
|
||||
4. 预期结果验证
|
||||
|
||||
确保遵循 TDD 原则,测试先于代码存在。
|
||||
"""
|
||||
|
||||
response = self.agent.generate_reply(
|
||||
messages=[{"role": "user", "content": prompt}]
|
||||
)
|
||||
|
||||
test_content = response if isinstance(response, str) else str(response)
|
||||
|
||||
# 保存测试文件
|
||||
test_file = self.workspace_dir / "test_battery_health.py"
|
||||
with open(test_file, 'w', encoding='utf-8') as f:
|
||||
f.write(test_content)
|
||||
|
||||
print(f"✅ 测试用例已生成:{test_file}")
|
||||
return test_content
|
||||
|
||||
def create_bdd_scenarios(self, srs_content: str) -> str:
|
||||
"""
|
||||
创建 BDD 风格的测试场景
|
||||
|
||||
Args:
|
||||
srs_content: SRS 文档内容
|
||||
|
||||
Returns:
|
||||
BDD 测试场景描述
|
||||
"""
|
||||
prompt = f"""
|
||||
请根据 SRS 创建 BDD (Behavior-Driven Development) 测试场景:
|
||||
|
||||
{self._truncate(srs_content, 2000)}
|
||||
|
||||
请使用 Given-When-Then 格式描述每个测试场景:
|
||||
- Feature: 功能描述
|
||||
- Scenario: 场景描述
|
||||
- Given: 前置条件
|
||||
- When: 操作
|
||||
- Then: 预期结果
|
||||
|
||||
输出为 Markdown 格式。
|
||||
"""
|
||||
|
||||
response = self.agent.generate_reply(
|
||||
messages=[{"role": "user", "content": prompt}]
|
||||
)
|
||||
|
||||
bdd_content = response if isinstance(response, str) else str(response)
|
||||
|
||||
# 保存 BDD 场景文件
|
||||
bdd_file = self.workspace_dir / "bdd_scenarios.md"
|
||||
with open(bdd_file, 'w', encoding='utf-8') as f:
|
||||
f.write(bdd_content)
|
||||
|
||||
print(f"✅ BDD 场景已生成:{bdd_file}")
|
||||
return bdd_content
|
||||
|
||||
def analyze_test_coverage(self, test_code: str, srs_content: str) -> Dict[str, Any]:
|
||||
"""
|
||||
分析测试覆盖率
|
||||
|
||||
Args:
|
||||
test_code: 测试代码
|
||||
srs_content: SRS 文档
|
||||
|
||||
Returns:
|
||||
覆盖率分析报告
|
||||
"""
|
||||
prompt = f"""
|
||||
请分析以下测试代码对 SRS 需求的覆盖情况:
|
||||
|
||||
SRS 需求:
|
||||
{self._truncate(srs_content, 1500)}
|
||||
|
||||
测试代码:
|
||||
{self._truncate(test_code, 2000)}
|
||||
|
||||
请输出:
|
||||
1. 已覆盖的需求列表
|
||||
2. 未覆盖的需求列表
|
||||
3. 覆盖率百分比
|
||||
4. 改进建议
|
||||
"""
|
||||
|
||||
response = self.agent.generate_reply(
|
||||
messages=[{"role": "user", "content": prompt}]
|
||||
)
|
||||
|
||||
coverage_report = response if isinstance(response, str) else str(response)
|
||||
|
||||
# 保存报告
|
||||
report_file = self.workspace_dir / "coverage_report.md"
|
||||
with open(report_file, 'w', encoding='utf-8') as f:
|
||||
f.write(coverage_report)
|
||||
|
||||
return {"report": coverage_report, "file": str(report_file)}
|
||||
|
||||
def _truncate(self, text: str, max_length: int) -> str:
|
||||
"""截断文本以避免超出上下文限制"""
|
||||
if len(text) <= max_length:
|
||||
return text
|
||||
return text[:max_length] + "... [内容已截断]"
|
||||
|
||||
def run_tests(self, test_file_pattern: str = "test_*.py") -> Dict[str, Any]:
|
||||
"""
|
||||
执行测试(需要实际运行 pytest)
|
||||
|
||||
Args:
|
||||
test_file_pattern: 测试文件模式
|
||||
|
||||
Returns:
|
||||
测试结果字典
|
||||
"""
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
try:
|
||||
# 使用 pytest 执行测试
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "pytest",
|
||||
str(self.workspace_dir / test_file_pattern),
|
||||
"-v", "--tb=short"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
return {
|
||||
"success": result.returncode == 0,
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr,
|
||||
"returncode": result.returncode
|
||||
}
|
||||
except subprocess.TimeoutExpired:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "测试执行超时"
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def create_qa_agent(llm_config: Optional[Dict] = None) -> AssistantAgent:
|
||||
"""
|
||||
创建 QA Agent(AutoGen 原生格式)
|
||||
|
||||
Args:
|
||||
llm_config: LLM 配置
|
||||
|
||||
Returns:
|
||||
AutoGen AssistantAgent 实例
|
||||
"""
|
||||
config = llm_config or get_agent_llm_config("QA_Agent")
|
||||
|
||||
agent = AssistantAgent(
|
||||
name="QA_Agent",
|
||||
system_message=QA_PROMPT,
|
||||
llm_config=config,
|
||||
description="资深测试工程师",
|
||||
human_input_mode="NEVER"
|
||||
)
|
||||
|
||||
return agent
|
||||
Reference in New Issue
Block a user