基于AI大模型,将自然语言需求自动转化为结构化测试用例
📅 2026/7/7 5:51:26
👁️ 阅读次数
📝 编程学习
当下的AI技术迅猛渗透到各领域,对软件测试也造成不小的冲击。对测试从业者而言,无需畏惧 AI 的冲击,更应聚焦自身核心能力的提升。
以下分享了如何利用AI(通义大模型),将日常需求转化为测试用例,并自动生成到AgileTC测试用例管理平台中。
(一)核心思路
1、调用AI生成测试用例
用户输入PRD文本 → 构造Prompt → 调用DashScope API → 获取AI返回的JSON
prd_text = input("请输入需求描述: ").strip() ai_generator = QwenAIGenerator(api_key="") #通义api的key raw_test_cases = ai_generator.generate_from_prd(prd_text) print("AI返回的json:",raw_test_cases)class QwenAIGenerator: """使用通义千问API生成测试用例""" def __init__(self, api_key: str): self.api_key = api_key dashscope.api_key = api_key def generate_from_prd(self, prd_text: str) -> List[TestCase]: """ 通过通义千问API生成测试用例 要求模型返回严格的JSON格式,便于解析 """ prompt = f""" 你是一个资深测试工程师。请根据以下需求文档(PRD)内容,生成测试用例。 需求内容: {prd_text} 请严格按照以下JSON格式输出,不要包含任何其他解释或文本,只输出json数组: [ {{ "title": "用例标题", "steps": "步骤1\n步骤2", "expected": "结果1\n结果2", "precondition": "前置条件", "priority": "P0", "module": "所属模块", "tags": ["标签1", "标签2"] }} ] """ try: # 调用通义千问API response = dashscope.Generation.call( model='qwen-plus', prompt=prompt, temperature=0.5 ) # 提取模型返回的文本 content = response.output['text'] print(f"🤖 AI原始返回: {content}") # 调试用:打印AI返回的原始内容 except Exception as e: print(f"❌ 解析或调用异常: {e}") return []2、解析AI返回结果
AI返回的JSON字符串 → json.loads() 解析 → 字典列表 List[Dict]
# 提取模型返回的文本 if response.status_code == 200: content = response.output['text'] print(f"🤖 AI原始返回: {content}") # 调试用:打印AI返回的原始内容 # 清洗AI返回内容,提取JSON部分 content = self._extract_json(content) # 尝试解析JSON case_dicts = json.loads(content) # 确保每个字典的字段完整 for case_dict in case_dicts: case_dict.setdefault("title", "未命名用例") case_dict.setdefault("steps", "") case_dict.setdefault("expected", "") case_dict.setdefault("precondition", "") case_dict.setdefault("priority", "P2") case_dict.setdefault("module", "默认模块") # 确保tags是列表 tags = case_dict.get("tags", []) if isinstance(tags, str): case_dict["tags"] = [tags] return case_dicts else: print(f"❌ API调用失败: {response.message}") return [] def _extract_json(self, text: str) -> str: """ 从AI返回的文本中提取纯JSON内容 AI可能会返回 ```json [...] ``` 这样的格式 """ import re # 尝试匹配 ```json ... ``` 代码块 match = re.search(r'```(?:json)?\s*\n?(.*?)\n?\s*```', text, re.DOTALL) if match: return match.group(1).strip() # 尝试匹配纯JSON数组 match = re.search(r'(\[.*\])', text, re.DOTALL) if match: return match.group(1).strip() # 都没有匹配到,返回原文 return text.strip()3、转换为AgileTC思维导图格式
字典列表 → 构建思维导图树 → 输出AgileTC格式的JSON字符串
| 方法 | 作用 |
|---|---|
build_case_content(test_points) | 主入口,遍历测试点列表,构建完整的思维导图树 |
_create_text_node(label, text) | 创建叶子节点,如"标签: 冒烟测试" |
_create_list_node(label, text) | 创建带子节点的父节点,按换行符拆分,每行一个子节点 |
_generate_id() | 为每个节点生成唯一ID(UUID截取) |
class MindMapBuilder: """构建AgileTC需要的思维导图格式""" def build_case_content(self, test_points: List[Dict]) -> str: """ 构建思维导图格式的caseContent test_points: 包含多个测试点的列表,每个测试点是一个字典 """ # 构建完整的思维导图结构 mindmap = { "root": { "data": { "id": self._generate_id(), "created": int(time.time() * 1000), "text": test_points[0].get("module", "测试用例") # 中心主题使用模块名或默认名 }, "children": self._build_all_children(test_points) }, "template": "default", "theme": "fresh-blue", "version": "1.4.43", "base": 0 } return json.dumps(mindmap, ensure_ascii=False) def _build_all_children(self, test_points: List[Dict]) -> List[Dict]: """ 构建所有测试点的子节点 每个测试点作为一个大的分支(父节点),下面包含步骤和预期 """ children = [] for point in test_points: # 1. 创建测试点分支(父节点) point_node = { "data": { "id": self._generate_id(), "created": int(time.time() * 1000), "text": f"【{point.get('priority', 'P2')}】{point.get('title', '无标题')}" }, "children": [] } # 2. 添加步骤子节点 if point.get("steps"): steps_node = self._create_list_node("执行步骤", point["steps"]) point_node["children"].append(steps_node) # 3. 添加预期子节点 if point.get("expected"): expected_node = self._create_list_node("预期结果", point["expected"]) point_node["children"].append(expected_node) # 4. 添加标签(如果需要) if point.get("tags"): tags_node = self._create_text_node("标签", ", ".join(point["tags"])) point_node["children"].append(tags_node) children.append(point_node) return children def _generate_id(self) -> str: """ 生成唯一节点ID AgileTC使用类似UUID的格式作为节点标识 """ return str(uuid.uuid4()).replace("-", "")[:20] def _create_text_node(self, label: str, text: str) -> dict: """ 创建单个文本节点 用于展示标签、前置条件等单行文本信息 生成的结构示例: 标签: 冒烟测试, 登录模块 """ return { "data": { "id": self._generate_id(), "created": int(time.time() * 1000), "text": f"{label}: {text}" }, "children": [] } def _create_list_node(self, label: str, text: str) -> dict: """ 创建列表节点(带子节点) 用于展示步骤、预期结果等多行信息 每一行变成一个子节点 生成的结构示例: 执行步骤 ├── 1. 打开登录页面 ├── 2. 输入手机号 └── 3. 点击获取验证码 """ # 按换行符拆分,过滤空行 lines = [line.strip() for line in text.split("\n") if line.strip()] # 构建子节点列表 children = [] for line in lines: children.append({ "data": { "id": self._generate_id(), "created": int(time.time() * 1000), "text": line }, "children": [] }) # 返回带子节点的父节点 return { "data": { "id": self._generate_id(), "created": int(time.time() * 1000), "text": label }, "children": children }mindmap_builder = MindMapBuilder() case_data = { "productLineId": AGILETC_CONFIG["productLineId"], "channel": AGILETC_CONFIG["channel"], "creator": AGILETC_CONFIG["username"], "caseType": 1, # 用例标题可以取第一个用例的标题,或者自定义 "title": f"综合测试用例:{raw_test_cases[0].get('module', '功能测试')}", "description": f"该用例包含 {len(raw_test_cases)} 个测试点", # 🔴 关键:将所有测试点传入 builder "caseContent": mindmap_builder.build_case_content(raw_test_cases), "priority": 1, "status": 1, "folderId": 1, "module": raw_test_cases[0].get("module", "默认模块"), "tags": "AI生成,综合用例", "createTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "updateTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "projectId": AGILETC_CONFIG["project_id"], "autoStatus": 0, "reviewStatus": 0, "version": "1.0", "bizId": AGILETC_CONFIG["bizId"], "creator": AGILETC_CONFIG["creator"], "productLineId": AGILETC_CONFIG["productLineId"] }4、对接测试用例平台
AgileTC格式JSON → 写入文件 / 调用AgileTC接口导入
AGILETC_CONFIG = { "base_url": "https://testacthuyitool.jidiandian.cn", "username": "", # 你的用户名 "bizId": "-1", # 默认文件夹ID "project_id": 1, "channel": 1, "caseType": 0, "creator": "", "productLineId": 1 } class AgileTCClient: def __init__(self, config: Dict): self.base_url = config["base_url"].rstrip('/') self.username = config["username"] self.bizId = config["bizId"] self.project_id = config["project_id"] self.channel = config["channel"] self.caseType = config["caseType"] self.creator = config["creator"] self.productLineId = config["productLineId"] self.session = requests.Session() self.session.cookies.set('username', self.username) self.headers = { "User-Agent": "Mozilla/5.0", "Content-Type": "application/json;charset=UTF-8", "Accept": "application/json, text/plain, */*", } def create_test_case(self, case_data: Dict) -> Dict: """创建测试用例 - 针对你的API响应格式修复""" url = f"{self.base_url}/api/case/create" print(f"📤 创建用例: {case_data.get('title')}") try: response = self.session.post(url, json=case_data, headers=self.headers, timeout=10) print(f"📡 响应状态码: {response.status_code}") print(f"📡 响应内容: {response.text[:200]}...") # 解析JSON响应 result = response.json() print(f"📡 解析后的JSON: {result}") # 🔴 关键修复:正确处理data字段 if result.get("code") == 200: data_value = result.get("data") # 检查data的类型 if isinstance(data_value, dict): # data是字典,包含id字段 case_id = data_value.get("id", "未知") print(f"✅ 创建成功!用例ID: {case_id}") elif isinstance(data_value, (int, str)): # data是整数或字符串,直接就是用例ID case_id = data_value print(f"✅ 创建成功!用例ID: {case_id}") else: # 其他类型 case_id = "未知" print(f"✅ 创建成功!data字段: {data_value}") return { "success": True, "code": 200, "msg": result.get("msg", "成功"), "data": {"id": case_id} if not isinstance(data_value, dict) else data_value, "raw_response": result } else: error_msg = result.get("msg", f"错误码: {result.get('code')}") print(f"❌ 创建失败: {error_msg}") return { "success": False, "code": result.get("code"), "msg": error_msg, "error": error_msg } except Exception as e: print(f"💥 请求异常: {e}") return {"success": False, "error": str(e)} client = AgileTCClient(AGILETC_CONFIG) result = client.create_test_case(case_data) if result.get("success"): print(f"✅ 所有测试点已合并创建成功!") else: print(f"❌ 创建失败")(二)注意点
| 模型名称 | 定位 | 说明 |
|---|---|---|
qwen-max | 旗舰 | 效果最好,最贵 |
qwen-plus | 均衡 | 效果和成本平衡,推荐 |
qwen-turbo | 快速 | 速度快,成本低 |
博主一开始用的qwen-max效果最好但贵,很快就账号欠费了,后来换成qwen-plus性价比更高,生成测试用例完全够用。
(三)运行效果
总结:用AI大模型把自然语言的需求文档,自动转成结构化的测试用例,再转换成AgileTC思维导图格式,实现从需求到用例的一键生成。
编程学习
技术分享
实战经验