☰
AI测试用例生成实战:规则与LLM结合的需求文档自动化解析
2026/10/10 9:55:07 网站建设 项目流程

简介:这是一款面向测试人员、产品经理及业务分析人员的 Windows 桌面工具,用于将 PRD、自然语言需求、Office/PDF 文档及图片需求自动转换为结构化功能测试用例。工具支持 DeepSeek、豆包、千问、智谱 GLM 及 OpenAI 兼容接口,内置本地 OCR、需求点预分析、长文档自动分段、需求覆盖矩阵、用例质量评分、缺口补齐、历史版本对比与多格式导出等能力。资源包含 1 个 docx 操作手册,约 7.4MB,内容覆盖安装启动、模型配置、文档导入、OCR 识别、生成结果查看、用例编辑补齐、历史对比及导出说明,并附常见问题排查方法。该手册面向实际使用场景,步骤清晰、截图完整,便于快速上手与落地部署;目前已有 179 人学习下载,适合需要在本地搭建 AI 测试用例生成流程的团队或个人参考。

1. 需求文档自动转测试用例:先看看这块“AI+QA”能做多深

前阵子接了个紧急版本,需求文档一百多页,光“用户点击分享后生成链接”这种半句话,评审会上就能吵十分钟。以前拉测试用例,一个人对着文档坐一下午,产出还老漏场景。我把这套“AI自动化识别需求文档生成测试用例工具”跑了一遍:需求文档先按章节切块,再交给本地部署的AI接口识别关键信息,最后按统一模板批量生成用例初稿。核心思路是规则做约束、AI做语义理解,生成结果不直接上回归,而是当人工审核的加速器。如果你是测试工程师、测试开发,或者被大量PRD逼疯的质量负责人,这篇文章值得往下看。下面按“原理—预处理—生成—排查—进阶”的顺序,把每个环节的参数和坑都拆开。

2. 核心原理:规则与LLM双路线,为什么我选了LLM主导

2.1 先把“自动化识别需求文档”这件事拆开

所谓“AI识别需求文档”,本质上做的是两件事:第一是从非结构化文本里抽信息,第二是把抽出来的信息补成测试用例需要的结构。前一件靠格式解析,后一件靠语义理解。需求文档通常是Word或Markdown,里面混杂了目录、修订记录、业务背景、接口说明、操作步骤。要让AI稳定产出用例,第一步就得让文档变得“像食材一样干净”。

规则驱动是很多老测试工具的思路:写死一堆正则,比如“点击”“输入”“选择”“应显示”“预期”这些关键词一旦出现,就把它所在的句子抓出来当操作步骤或预期结果。这种方法在格式高度统一的PRD里非常好用,零幻觉,执行速度快,早期常见做法就是纯正则抓取,抓一个“步骤:”“预期结果:”这种带标签的段落几乎百发百中。但一旦需求写成大白话,比如“用户在列表页勾选多条数据后,点击批量导出按钮,系统要能正常生成文件”,传统正则就抓瞎了。

import re # 理想情况:需求按“步骤:xxx”和“预期:xxx”写 step_pattern = re.compile(r'(?:步骤|操作)[::]\s*(.+)') exp_pattern = re.compile(r'(?:预期|预期结果|验证点)[::]\s*(.+)') text = "步骤:点击批量导出按钮\n预期:系统生成Excel文件" step_match = step_pattern.search(text) exp_match = exp_pattern.search(text) print(step_match.group(1) if step_match else None) # 点击批量导出按钮 print(exp_match.group(1) if exp_match else None) # 系统生成Excel文件

这段代码的逻辑很清楚:用两个正则分别匹配“步骤”“预期”两个关键字后面的内容。参数上需要注意,中文需求文档里冒号经常混用全角“:”和半角“:”,正则里要把两种都写进去;如果文档里写的是“操作要求”“结果校验”这类变体标签,这段正则立刻失效。它的定位是给LLM做“兜底”,而不是单独扛起整个解析任务。

2.2 LLM理解能力强,但必须给它套上笼头

LLM路线的优势在“语义补全”。同样一句“用户点击分享后生成链接”,规则只能拆出“点击分享”和“生成链接”两个动作,但如果有经验的测试看到这句话,一定会追问:链接有效期多久?无权限用户点分享会怎样?链接被多次复制会不会失效?这些补充场景靠正则写不出来,只能靠模型推理。

我在这套工具里的默认策略是“LLM主导生成、规则兜底校验”。生成侧,把需求片段和一段结构化的系统提示词一起发给模型,让它输出固定格式的JSON数组;校验侧,先做JSON格式解析,再做必填字段检查,步骤为空或预期结果为空的条目一律返回重试,重试一次仍失败就标记成“人工补充队列”,绝不让脏数据混进导出文件。

# 调用OpenAI兼容接口的示意代码 client = OpenAICompatClient(base_url="http://localhost:8080/v1", api_key="local") resp = client.chat.completions.create( model="local-llm", messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": block_text} ], temperature=0.2, top_p=0.9, max_tokens=1500, ) raw = resp.choices[0].message.content

参数选型上,temperature设0.2是为了让模型尽量贴着原文生成,不要自由发挥太远;max_tokens设1500,是给一次生成3到8条用例留足空间,如果片段特别长,可以提到2000。top_p保持0.9,属于“允许一点发散但不失控”的折中值。常见误用是拿默认对话模型的temperature=0.7直接跑,结果同一段需求两次生成完全不一样,后面去重时头大。

2.3 工具整体工作流与各模块边界

整个流程分成六段:文档解析、文本清洗、场景切块、LLM生成、格式校验、结果导出。文档解析负责把Word/PDF/Markdown统一转成纯文本;文本清洗负责去掉目录、页眉、修订记录这类噪音;场景切块决定哪些文本作为一个整体送给模型;LLM生成负责任务的语义理解和用例初稿;格式校验把模型的自由输出拉回标准结构;导出模块把用例写成Excel或JSON,方便人工审核和后续导入用例管理平台。

阶段输入输出主要风险
文档解析原始PRD纯文本图片型PDF文字丢失
文本清洗纯文本干净文本把正文当页眉删掉
场景切块干净文本文本块切块切碎业务场景
LLM生成文本块JSON数组幻觉、重复、格式乱
格式校验JSON数组结构化用例字段缺、步骤空
结果导出结构化用例Excel/JSON编码错、字段映射错

这套工作流的边界感很重要:切块决定了模型“看什么”,Prompt决定模型“怎么写”,校验决定“能不能出去”。很多翻车不是模型不够聪明,而是前一步切块把场景切碎了,或者后一步校验没拦住脏数据。

3. 需求文本预处理:清洗、切块与关键信息抽取

3.1 文档清洗:先把PRD里的噪音清掉

我不建议直接把Word转出来的原文丢给模型。PRD里普遍有目录、页码、修订历史、评审意见、密级页,这些内容跟业务功能没有关系,模型读到后容易把“作者:某某”“版本:V1.2”当成用例素材。清洗做得好,后面的生成质量能提升一个档。最常用的清洗手段是按行过滤,配合少量关键词规则。

def clean_doc_text(raw: str) -> str: lines = raw.splitlines() cleaned = [] for line in lines: s = line.strip() if not s: continue # 去掉“1.1 概述 .... 5”这类目录行 if re.search(r'^[\d\.]+\s+\S+.*\.{2,}\s*\d+$', s): continue # 去掉页眉页脚与安全声明 if s.startswith(("项目编号", "文档密级", "修订记录", "审批记录")): continue # 删除评审意见里的“【评审】”段落 if s.startswith("【评审】"): continue cleaned.append(s) return "\n".join(cleaned)

这段代码的过滤顺序是有讲究的:先删空行,再删目录,再删文档元信息,最后删评审痕迹。目录行的特征是标题文字和页码之间有一串省略号,正则里用\.{2,}匹配;页眉页脚固定前缀可以做成配置列表,因为不同项目的PRD模板不一样。特别提醒:不要用全局正则把所有“版本”字样都删掉,正文里出现“版本升级后”就是正常业务描述,误删会直接丢功能信息。

3.2 按业务场景切块:chunk_size和overlap的参数怎么选

清洗完之后是切块。切块的目的是让每次喂给模型的文本足够聚焦,同时不超出模型的上下文窗口。实际项目中我常用“先按标题切,再按长度兜底”的两级策略:如果需求文档有明确的章节结构,直接按一级标题、二级标题把文本拆成业务块;如果文档是流水账式描述,就按句号和换行做分段,再用最大长度做二次强制切割。

def split_into_blocks(text, max_chunk=800, overlap=80): # 匹配“第一章”或“1.1 概述”两种标题写法 headings = list(re.finditer(r'(?m)^(第[一二三四五六七八九十]+[章节]|[\d\.]+\s+\S+)', text)) blocks = [] for i in range(len(headings)): start = headings[i].start() end = headings[i + 1].start() if i + 1 < len(headings) else len(text) seg = text[start:end].strip() if len(seg) > max_chunk: # 超长块按句号二次切分 for sub in re.split(r'(?<=[。;])', seg): if sub.strip(): blocks.append(sub.strip()[:max_chunk]) else: blocks.append(seg) # 相邻块拼接时保留overlap避免上下文断层 merged = [] for b in blocks: if merged and len(merged[-1]) + len(b) <= max_chunk + overlap: merged[-1] += "\n" + b else: merged.append(b) return merged

参数上,max_chunk设800字是我在本地部署模型上的习惯值,上下文窗口小一点的模型就降到500,窗口大的可以放到1500,但要考虑生成时max_tokens也要跟着调整。overlap设80字,作用是把上一段的结尾带进下一段,防止模型切断了上一段的逻辑。常见误用是把overlap设为0,结果“点击提交按钮,系统校验通过后跳转详情页”被切在两块里,第二块只有“跳转详情页”,生成用例时完全没有操作入口。

3.3 关键信息抽取:哪些字段该用正则,哪些该交给模型

切块之后,还需要给每块补上“元信息”:需求编号、所属模块、需求标题、前置条件、操作步骤、预期结果、用例类型、优先级。这里的原则是“能正则就正则,正则认不出来再交给模型”。

def extract_fields(block_text, module_name="默认模块"): fields = { "module": module_name, "req_id": None, "title": None, "precondition": None, "steps": [], "expected": [], } # 需求编号:通常是“REQ-2024-001”这类格式 req_id = re.search(r'(REQ[-_]\d{4}[-_]\d{3,})', block_text) if req_id: fields["req_id"] = req_id.group(1) # 步骤:优先匹配带编号的“1. 点击xxx”列表 steps = re.findall(r'(?m)^\s*\d+[\.、]\s*(.+)', block_text) if steps: fields["steps"] = steps return fields

这里我用正则先抓需求编号和编号列表步骤,抓不到的部分在后续生成阶段会由Prompt里的规则补。为什么不全部交给模型?因为模型抽取字段的延迟和成本比正则高得多,而且对“REQ-2024-005”这种固定格式,正则100%命中,模型偶尔还会写错成“REQ2024005”。反过来,前置条件和隐含分支这种正则永远写不出来的字段,就必须靠模型补全。实际经验是:固定格式字段10个里9个用正则可以搞定,剩下一个正则搞不定的,往往是文档里同时出现多个需求编号,模型在这里反而比正则灵活。

4. 测试用例批量生成:Prompt设计、参数配置与输出校验

4.1 Prompt模板:把用例结构焊死在系统提示词里

AI生成用例,决定输出质量的第一因素不是模型,而是Prompt。一个松散的Prompt会让模型自由发挥,输出“验证一下XX功能”这种毫无操作性的废话;而把用例结构、覆盖策略、禁止事项全部写清楚,模型才会老老实实输出可执行的用例。我在工具里用的系统提示词大致是这个样子:

SYSTEM_PROMPT = """你是资深测试工程师,请根据需求片段生成测试用例。 只输出JSON数组,不要输出解释或Markdown。 每个用例包含以下字段: case_title: 用例标题 case_type: 正常流/异常流/边界流 precondition: 前置条件,可为空字符串 steps: 操作步骤数组,每步必须是可执行的操作 expected_result: 预期结果 priority: P0/P1/P2 要求: 1. 每个片段生成3到8条用例,优先覆盖正常流、异常流、边界流; 2. 所有步骤和预期结果必须能在需求片段中找到依据; 3. 找不到依据的预期结果写“待确认”,不要编造功能; 4. 没有操作内容的需求片段,输出空数组。"""

这个模板有几个关键设计。第一,把“case_type”限定为三种固定值,便于后续统计和过滤;第二,明确“找不到依据写待确认”,有效压制幻觉;第三,允许输出空数组,避免背景章节强行生成用例。很多新手会在system里写一堆形容词,比如“请仔细分析需求并生成高质量用例”,模型无法精确理解什么叫“高质量”,不如直接限定格式和数量。

4.2 模型生成参数:temperature、top_p、max_tokens怎么设

参数推荐值说明设置过高/过低的后果
temperature0.2控制随机性过高用例重复发散、过低照抄原文不补场景
top_p0.9控制候选词范围过高胡说八道、过低丢失边界场景
max_tokens1500~2000单次输出长度上限过短步骤被截断、JSON被截成残文
frequency_penalty0.3抑制重复词过高术语被改写、过低步骤反复出现

temperature是这里最值得调的参数。用例生成本质上是要在“忠于原文”和“适当补全”之间找平衡,我实际跑下来0.2到0.3是最稳的区间。调到0.7以上,模型有时会把同一条用例换个说法输两遍,或者为“点击按钮”脑补出“点击后弹窗确认”这种需求里没有的交互。max_tokens的设置要跟切块长度联动,800字的需求片段配1500的max_tokens一般够用,但如果提示词里要求覆盖异常流和边界流,单次输出8条用例可能会超,保险起见给到2000。

4.3 批量生成与导出:循环、重试、字段校验

批量生成的骨架是一个循环:每个文本块依次调用模型接口,解析返回结果,做字段校验,最后合并落盘。关键不在循环本身,而在三个容易被忽略的点:单块失败不能中断全流程、模型输出经常带Markdown代码块包裹、必填字段缺失必须能自动识别。

def batch_generate(blocks): all_cases = [] failed_blocks = [] for idx, block in enumerate(blocks): try: raw = call_llm(block, SYSTEM_PROMPT) cases = parse_json_from_llm(raw) valid = [] for c in cases: # 必填字段校验:步骤和预期结果不能空 if not isinstance(c.get("steps"), list) or len(c["steps"]) == 0: continue if not c.get("expected_result"): c["expected_result"] = "待确认" valid.append(c) all_cases.extend(valid) except Exception as e: failed_blocks.append({"idx": idx, "error": str(e), "block": block[:200]}) return all_cases, failed_blocks

逻辑说明:call_llm负责拼参数、调用接口、返回原文;parse_json_from_llm专门处理模型输出可能带的```json包裹或前后解释文字,取第一个被方括号包住的片段做json.loads;校验阶段用两步过滤,第一步剔除steps为空的残条,第二步把空预期结果替换成“待确认”。参数说明:failed_blocks只保留前200字预览,避免错误日志里塞满整段需求导致日志文件膨胀。

校验通过的用例可以导出成Excel。导出时字段顺序固定为:模块、需求编号、用例标题、用例类型、前置条件、步骤、预期结果、优先级。这样人工审核时只需要对照需求文档在Excel里逐行看,不需要额外学习工具的输出格式。另外连接池和超时也值得单独说:批量跑几百个块时,把并发控制在3到5个,单请求超时给到90秒,超过就重试一次,再失败进人工队列,比一味把并发开到10然后整批超时稳定得多。

5. 避坑排查:生成结果错的五种典型翻车现场

5.1 现象:JSON解析一直失败,批量任务卡在第一步

初跑这套流程时,批量生成跑到十几块就停,日志报“json.decoder.JSONDecodeError: Expecting value”,但单独调接口又是正常的。排查后发现模型返回的内容前后各包了一个json和,json.loads直接看到的是反引号。这类输出是模型基于训练习惯带出来的,跟模型版本和温度都有关系,几乎不可避免。

解决方式是在解析函数里先剥掉代码块标记,再提取第一个完整数组片段。

def parse_json_from_llm(raw): raw = raw.strip() # 剥掉```json ...```包裹 if raw.startswith("```"): raw = re.sub(r'^```[a-zA-Z]*\n?|\n?```$', '', raw) start, end = raw.find("["), raw.rfind("]") if start == -1 or end <= start: raise ValueError("no array found") return json.loads(raw[start:end + 1])

这段代码先用正则去掉代码块包裹的开闭标记,再用首尾方括号截出数组主体。经验是不要一上来就全套json.loads,先把最外层的Markdown剥掉,能解决九成解析失败。

5.2 现象:模型把“需求背景”当功能生成了一堆重复用例

某次处理一个后台系统的PRD,第一章叫“项目背景”,里面写了几段业务目标。模型把“系统需要支持高并发访问”这句话理解成需求,生成了一堆“验证系统在高并发下的表现”这种无法直接执行的用例,而且好几条内容几乎一样。

原因是切块时没有过滤背景类章节,模型拿到无操作内容的文本又被要求“生成3到8条用例”,只能硬编。解决分两步:清洗阶段维护一个标题黑名单,把“项目背景”“名词解释”“非功能需求”这类常见章节过滤掉;Prompt里同时加上“没有操作内容的需求片段,输出空数组”这条硬约束。双保险后这类重复基本绝迹。

5.3 现象:长文档后半段用例整体缺失,只看到前置条件没有步骤

还有一次是处理一份超过2万字的需求文档,切块时max_chunk设到了1500,结果后半段的块经常只有前置条件没有操作步骤,甚至出现一个块只输出一条用例的情况。检查发现模型的上下文窗口被长片段撑满,输出被截断,JSON在“steps”字段处断掉,校验时把steps非空的残条也放行了。

解决方式是降低max_chunk到700,overlap提到100,同时在校验逻辑里增加一条:steps为空或只有一条的用例强制加入人工复核队列。从此之后长文档的丢失率从三成降到个位数。

5.4 现象:模型编造功能,把“应提示”脑补成“弹窗确认”

需求原文写的是“输入非法格式时,系统应提示错误”,模型生成的预期结果却是“系统弹出确认弹窗,用户在弹窗中点击确认后关闭页面”。这种幻觉很隐蔽,表面看流程完整,实际上加了需求里根本不存在的交互,回归时照着用例做反而会把系统带偏。

原因在于Prompt里没有对“依据”做限制,模型默认按常见产品交互补全。解决方式是在system里写明“所有步骤与预期结果必须能在需求片段中找到依据,找不到依据的预期结果写‘待确认’”,同时在审核状态下增加一个“AI补全标记”字段,凡是模型自己补出来的前置条件和分支,导出时就标成黄色,人工审核时重点看黄色行。

5.5 现象:批量跑批超时,生成率只有六成还不报错

跑一个包含两百个文本块的需求集,耗时半小时,过程没报错,结果只导出了六成用例。排查后发现问题出于并发过大:同时开10个请求,本地模型接口连接被重置,异常被外层循环捕获后记录进failed_blocks,但日志没细看导致生成流程“假成功”。

解决方式是引入并发信号量限制为3,并把失败重试逻辑改成先休眠再重试,最多两轮,仍然失败才进人工队列。另外把每批结果实时落盘成JSON,即使中途进程被杀,已经生成的用例也不会丢。后来我每次跑批都会盯三个数字:成功块数、失败块数、重试次数,三者加不拢就说明有静默丢弃。

6. 进阶玩法:把生成的用例变成可持续复用的回归资产

单次批量生成只是第一步,用例资产要能跨版本复用,还得做三件事。

第一,给每条用例打上“需求编号+版本号”标签。需求文档不是一成不变的,下一版本只改一个字段,全量重跑会生成大量重复用例。我在工具里约定:录入新版本时先做文本差异diff,只把变更的文本块重新喂给AI生成,旧版本的用例保留在回归集里。第二,对跨版本积累的用例做去重合并。Excel里常有两个版本生成出标题不同但步骤完全相同的用例,我用“模块+步骤列表的hash值”做判重,步骤完全一致就直接合并,保留优先级高的那一条,避免回归集越来越大全是重复。第三,把人工审核状态沉淀成字段:已审核、待审核、AI待确认,每次提测前强制过滤“待确认”用例。在用例管理平台导入时,按模块字段自动映射到对应测试计划目录,省掉手动调整目录层级的时间。

字段生成初值审核后改
需求编号正则抽取人工修正
版本号当前文档版本后续版本迭代更新
审核状态待审核已审核/待确认
AI补全标记是/否人工复核后清除

最后讲一件我自己的血泪教训:一次回归测试,图省事直接用了AI生成的初稿,没做人工复核,漏掉了“token过期”这个分支场景,上线后线上才暴露出来。从那以后,我每次跑新版本需求都强制走一遍“预处理—切块—生成—校验—人工标记”这套流程,AI生成的结果只当第一版草稿,绝不让它直接上回归。希望这套拆解和参数经验能帮你在测试用例生成这件事上少踩几个坑。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询