168 lines
6.1 KiB
Python
168 lines
6.1 KiB
Python
|
|
# @line_count 200
|
|||
|
|
"""测试规范选择器,实现规则+AI混合选择策略"""
|
|||
|
|
from typing import List, Dict, Any, Optional, TYPE_CHECKING
|
|||
|
|
from .test_standard_loader import TestStandardLoader
|
|||
|
|
import json
|
|||
|
|
import re
|
|||
|
|
|
|||
|
|
if TYPE_CHECKING:
|
|||
|
|
from .api_client import APIClient
|
|||
|
|
|
|||
|
|
|
|||
|
|
class StandardSelector:
|
|||
|
|
"""测试规范选择器,实现规则+AI混合选择策略"""
|
|||
|
|
|
|||
|
|
def __init__(self, loader: TestStandardLoader, api_client: Optional['APIClient'] = None):
|
|||
|
|
"""
|
|||
|
|
初始化规范选择器
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
loader: 测试规范加载器
|
|||
|
|
api_client: API客户端,用于AI辅助选择
|
|||
|
|
"""
|
|||
|
|
self.loader = loader
|
|||
|
|
self.api_client = api_client
|
|||
|
|
self.mapping_rules = loader.get_requirement_mapping()
|
|||
|
|
self.keyword_mapping = loader.get_keyword_mapping()
|
|||
|
|
|
|||
|
|
def select_standards(self, requirement: Dict[str, Any], use_ai: bool = True) -> List[str]:
|
|||
|
|
"""
|
|||
|
|
为需求选择适用的测试规范
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
requirement: 需求字典,包含requirement_type、description等
|
|||
|
|
use_ai: 是否使用AI辅助选择(当规则匹配不足时)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
测试规范ID列表
|
|||
|
|
"""
|
|||
|
|
# 第一步:规则匹配
|
|||
|
|
rule_based = self._rule_based_selection(requirement)
|
|||
|
|
|
|||
|
|
# 第二步:如果规则匹配不足,使用AI补充
|
|||
|
|
if use_ai and len(rule_based) < 2 and self.api_client:
|
|||
|
|
ai_based = self._ai_based_selection(requirement)
|
|||
|
|
# 合并去重
|
|||
|
|
all_standards = list(set(rule_based + ai_based))
|
|||
|
|
return all_standards
|
|||
|
|
|
|||
|
|
return rule_based
|
|||
|
|
|
|||
|
|
def _rule_based_selection(self, requirement: Dict[str, Any]) -> List[str]:
|
|||
|
|
"""
|
|||
|
|
基于规则的规范选择
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
requirement: 需求字典
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
测试规范ID列表
|
|||
|
|
"""
|
|||
|
|
standards = []
|
|||
|
|
req_type = requirement.get('requirement_type', '')
|
|||
|
|
req_desc = requirement.get('description', '')
|
|||
|
|
|
|||
|
|
# 1. 需求类型映射
|
|||
|
|
if req_type in self.mapping_rules:
|
|||
|
|
mapping = self.mapping_rules[req_type]
|
|||
|
|
# 主要测试类型
|
|||
|
|
standards.extend(mapping.get('primary', []))
|
|||
|
|
# 次要测试类型
|
|||
|
|
standards.extend(mapping.get('secondary', []))
|
|||
|
|
# 条件性测试类型
|
|||
|
|
conditionals = mapping.get('conditional', {})
|
|||
|
|
if '有界面' in conditionals and ('界面' in req_desc or '显示' in req_desc):
|
|||
|
|
standards.extend(conditionals['有界面'])
|
|||
|
|
if '有性能要求' in conditionals and ('性能' in req_desc or '速度' in req_desc or '时间' in req_desc):
|
|||
|
|
standards.extend(conditionals['有性能要求'])
|
|||
|
|
if '安全关键' in conditionals and ('安全' in req_desc or '危险' in req_desc or '报警' in req_desc):
|
|||
|
|
standards.extend(conditionals['安全关键'])
|
|||
|
|
if '多软件交互' in conditionals and ('交互' in req_desc or '协同' in req_desc):
|
|||
|
|
standards.extend(conditionals['多软件交互'])
|
|||
|
|
if '性能相关' in conditionals and ('性能' in req_desc):
|
|||
|
|
standards.extend(conditionals['性能相关'])
|
|||
|
|
if '安全相关' in conditionals and ('安全' in req_desc):
|
|||
|
|
standards.extend(conditionals['安全相关'])
|
|||
|
|
|
|||
|
|
# 2. 关键词匹配
|
|||
|
|
for keyword, test_types in self.keyword_mapping.items():
|
|||
|
|
if keyword in req_desc:
|
|||
|
|
standards.extend(test_types)
|
|||
|
|
|
|||
|
|
# 3. 接口信息检测
|
|||
|
|
if requirement.get('interface_info'):
|
|||
|
|
standards.append('外部接口测试')
|
|||
|
|
|
|||
|
|
# 去重并返回
|
|||
|
|
return list(set(standards))
|
|||
|
|
|
|||
|
|
def _ai_based_selection(self, requirement: Dict[str, Any]) -> List[str]:
|
|||
|
|
"""
|
|||
|
|
基于AI的规范选择(当规则匹配不足时使用)
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
requirement: 需求字典
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
测试规范ID列表
|
|||
|
|
"""
|
|||
|
|
if not self.api_client:
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
# 获取所有测试规范名称
|
|||
|
|
all_standards = self.loader.get_all_standards()
|
|||
|
|
standard_names = [f"{i+1}. {std.get('name', '')}" for i, std in enumerate(all_standards)]
|
|||
|
|
|
|||
|
|
prompt = f"""根据以下需求,从14个测试类型中选择最适用的3-5个:
|
|||
|
|
|
|||
|
|
{chr(10).join(standard_names)}
|
|||
|
|
|
|||
|
|
需求类型:{requirement.get('requirement_type', '未知')}
|
|||
|
|
需求描述:{requirement.get('description', '')}
|
|||
|
|
|
|||
|
|
请只返回测试类型的名称列表,格式为JSON数组,例如:["功能测试", "性能测试", "边界测试"]
|
|||
|
|
不要包含其他说明文字。"""
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
response = self.api_client.call_api(prompt)
|
|||
|
|
# 尝试解析JSON
|
|||
|
|
test_types = self._parse_ai_response(response)
|
|||
|
|
return test_types
|
|||
|
|
except Exception as e:
|
|||
|
|
# 如果AI选择失败,返回空列表
|
|||
|
|
print(f"AI选择失败: {str(e)}")
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
def _parse_ai_response(self, response: str) -> List[str]:
|
|||
|
|
"""
|
|||
|
|
解析AI响应,提取测试类型列表
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
response: AI响应文本
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
测试类型名称列表
|
|||
|
|
"""
|
|||
|
|
# 尝试直接解析JSON
|
|||
|
|
try:
|
|||
|
|
# 尝试提取JSON数组
|
|||
|
|
json_match = re.search(r'\[.*?\]', response, re.DOTALL)
|
|||
|
|
if json_match:
|
|||
|
|
json_str = json_match.group(0)
|
|||
|
|
test_types = json.loads(json_str)
|
|||
|
|
if isinstance(test_types, list):
|
|||
|
|
return test_types
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 如果JSON解析失败,尝试文本匹配
|
|||
|
|
all_standards = self.loader.get_all_standards()
|
|||
|
|
standard_names = [std.get('name', '') for std in all_standards]
|
|||
|
|
|
|||
|
|
found_types = []
|
|||
|
|
for name in standard_names:
|
|||
|
|
if name in response:
|
|||
|
|
found_types.append(name)
|
|||
|
|
|
|||
|
|
return found_types
|