222 lines
6.1 KiB
Python
222 lines
6.1 KiB
Python
"""
|
||
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
|