大模型驱动的需求文档到测试用例生成落地

日期:2026-07-18

本文为工程实践复盘,客户信息已脱敏;所述数据均为示意值。

一、项目背景

我们服务的某省级国资集团,其自研业务系统有 30 多个子系统,每次版本迭代都要配套更新测试用例。这个项目里,测试用例的编写长期依赖人工:需求评审后由测试同学逐条拆解功能点、手搓用例,平均一个中型需求要耗掉 2-3 人天。更麻烦的是,需求一旦变更,旧用例大量失效,回归覆盖常常补不全,线上漏测导致的缺陷只能靠生产环境暴露。我们当时评估下来,核心痛点是三件事:用例编写慢、需求变更后滞后、覆盖点靠人脑记忆不可控。

为此,我们采用自研的大模型私有化底座(vLLM 推理 + 向量检索层)搭了一套"需求到用例"生成流水线,并接入客户既有测试平台执行,目标是把测试同学从重复劳动里解放出来,同时把覆盖点做成可追溯、可审计的资产。

二、落地场景

这条流水线跑在客户内网的推理一体机上,输入是需求文档(PRD/Confluence 导出)和接口契约(OpenAPI/Swagger),输出是一批结构化测试用例。落地后主要覆盖三个动作:

第一,大模型读取需求与接口文档,按功能点抽取测试意图,生成包含正常流、异常流、边界值的用例初稿。

第二,自动标注每条用例覆盖的需求条目(traceability),并对照接口参数生成请求构造,输出机器可读的 schema。

第三,生成的用例通过 API 推送到客户既有的测试平台(基于 pytest + 自研调度)执行,执行结果回灌,形成"生成—执行—评审"闭环。

我们当时还接了内部的 AI 网关做统一鉴权与计量,测试团队按项目维度申请配额,调用链全程可观测。此外,生成阶段会同步产出一份覆盖矩阵报告,把"需求条目—用例—执行结果"三者映射到一张看板,版本发布前由 QA 负责人核查覆盖率缺口,未达标的需求不允许合入主干。这套机制让我们把"覆盖"从口头承诺变成了可量化、可追责的交付物,也顺带解决了过去"谁都说覆盖够了、真出事谁都没覆盖"的扯皮问题。

三、关键技术挑战与解决思路

挑战一:需求语义理解与边界抽取。 需求文档天然口语化、存在歧义,直接喂给模型容易生成"伪用例"。我们做法是先做文档切片与结构化:把 PRD 拆成"用户故事—验收标准—业务规则"三粒度,再用模型抽取每条业务规则的边界条件。例如一条"单笔订单金额上限 50 万元"的规则,我们要求模型同时产出上边界(500000)、下边界(0)与越界值(500001),并落库为约束表,后续用约束表反向校验用例是否真正覆盖了边界。

CREATE TABLE req_constraint (
  req_id       VARCHAR(32)  NOT NULL,
  rule_text    TEXT         NOT NULL,
  field        VARCHAR(64),
  lower_bound  DECIMAL(18,2),
  upper_bound  DECIMAL(18,2),
  violate_val  DECIMAL(18,2)
);

挑战二:用例可执行性与去重。 早期生成结果里重复用例占比高(约 28%),且部分用例缺请求体无法执行。我们引入两道关卡:先用 embedding 对用例标题做近邻去重(余弦阈值 0.86),再跑一个轻量子模型校验"请求是否可构造"。去重配置如下:

dedup:
  method: cosine
  threshold: 0.86
  embedding_model: bge-zh-base
validate:
  require_request_body: true
  require_expectation: true

挑战三:与既有测试平台对接。 客户测试平台只认固定 JSON schema,而模型输出是自由文本。我们定义了强约束输出 schema,用 function calling 强制模型按字段返回,再由适配层转成平台需要的 pytest 参数化模板。一次推送失败的日志帮我们定位了字段命名不一致:

2025-03-14 11:22:07 [WARN] adapter: field 'expect_code' missing in case#C-2081
2025-03-14 11:22:08 [INFO] adapter: dropped 6 cases, retry with schema fix

挑战四:人在回路评审。 生成不等于可用。我们设计了"AI 初稿 + 测试 owner 批注"的评审页面,每条用例带状态(待审/采纳/驳回),并显示模型给出的置信度与来源需求条目,方便 reviewer 快速判断。驳回理由回流做 few-shot 样本。实践里我们坚持:生成结果必须过评审才可入执行队列,评审结论进入版本库,保证可追溯;评审页面的采纳率也成了我们衡量模型效果的核心指标,从最初的约 55% 逐步爬升到约 77%。

四、效果数据

试运行约 8 周后,我们在 4 个子系统上做了对照统计。用例生成覆盖率(相对人工基线)提升至约 92%,人工改写率从 100% 降至约 23%,缺陷漏测率下降约 61%,单需求用例编写工时从约 2.5 人天降至约 0.6 人天。需要强调的是,这些均为脱敏示意值,非审计精确数。

指标改造前(基线)改造后(示意)变化
用例生成覆盖率约 64%约 92%提升约 28pp
人工改写率100%约 23%降至约 1/4
缺陷漏测率基线 100约 39下降约 61%
用例编写工时(人天/需求)约 2.5约 0.6下降约 76%

案例片段(已脱敏):需求到用例生成的核心 prompt 与 schema 片段。

角色:资深测试架构师。任务:基于以下需求条目生成可执行测试用例。 约束:每条用例必须含 {title, precond, steps, req_ref, expect_code, boundary}。 仅输出 JSON,禁止多余说明。需求条目:{{REQ_TEXT}}

模型返回片段(已脱敏):json {  "title": "单笔订单金额越界应被拒",  "precond": "用户已登录且购物车有效",  "steps": "POST /api/order {amount: 500001.00}",  "req_ref": "REQ-PAY-07",  "expect_code": 400,  "boundary": "upper=500000.00, violate=500001.00" }

五、可复用经验总结

第一,生成快但评审不可省。我们踩过的坑是初期迷信"全自动化",直接把生成结果灌入执行,结果一批无效用例污染了报表。后来把评审作为强制闸门,质量反而更稳。

第二,覆盖先于数量。模型很容易刷出几百条用例,但真正有价值的是边界与异常流。我们把"覆盖点可追溯"当成一等公民,用约束表反向校验覆盖完整性,比单纯追求用例条数更靠谱。

第三,强 schema 约束是落地关键。自由文本在工程链路里迟早要被结构化的,与其事后解析,不如在生成端就锁死 schema,配合 AI 网关做统一接入与计量,链路才稳。

第四,把人留在回路里。大模型是放大器,不是替代品;测试 owner 的批注意见是最宝贵的 few-shot 资产,持续回流才能越用越准。

第五,覆盖矩阵要当成发布闸门。我们最终把"需求覆盖率达标"设为合入主干的前置条件,让覆盖这件事有了强制力,也终结了团队内部关于"到底覆盖没覆盖"的反复拉扯。