
Yadda 3.0.0 这个版本号表面上只是 Yadda 项目的一次迭代但把标题里的后半句连起来看思路就很清楚了在 AI Agent 大量参与需求分析、代码生成和测试执行的时代BDD行为驱动开发到底应该怎么继续发挥作用。Yadda 是 JavaScript 生态里把 Gherkin 场景和可执行测试步骤粘合起来的库它解决的问题很实在业务需求用自然语言描述成 Feature 文件测试代码写成步骤定义然后由执行器跑起来。适合谁看写 Node.js 后端、打算接 AI 编程和 AI 测试工具、又不想让测试变成一堆一次性脚本的工程师都可以直接往下读。最值得关注的点不是它的某个命令而是它提供了一套稳定边界AI 生成代码再快也必须在业务场景里验证。1. Yadda 是什么为什么 AI Agent 时代还要谈 BDD1.1 BDD 不是“用自然语言写测试”很多人第一次接触 BDD会误以为它只是把测试用例翻译成英文或者中文。实际上 BDD 的核心不是语言而是行为。一个 Feature 里写的是用户或者系统能做的一件具体事情这些事情用 Given-When-Then 三段式描述先给定前置条件再触发动作最后看结果。BDD 的目标是让产品、开发、测试坐在一起对着同一份描述达成共识。Yadda 在这个链条里做的事情非常聚焦。它不接管整个测试框架不做断言也不负责生成报告。它只处理两件事把 Feature 文本解析成一个个场景再把场景里的每一步映射到 JavaScript 步骤函数上。所以你完全可以把它嵌进 Mocha、Jest 或者 Node 内置的测试逻辑里而不是像 Cucumber 那样工程结构更重、目录更固定。轻量是 Yadda 最明显的定位。正因为它轻量在 AI 参与开发的背景下反而更有优势。AI 可以很快生成一份场景草稿也可以生成一堆步骤定义但如果整条链路被绑定在一套僵化的目录结构和测试框架里AI 生成结果就越难回溯。Yadda 保持小意味着你可以把 AI 生成的内容快速丢进现有测试链路里验证。1.2 AI Agent 让 BDD 从“可选规范”变成“必要护栏”现在团队讨论 AI 编程、AI Coding、AI 测试时大多集中在怎么让模型生成代码、怎么自动补充用例、怎么让智能体自动修复失败任务。AI 确实能干这些事但有一个问题很容易被忽略模型生成的测试代码如果只是“自己写代码、自己验证自己”它的断言往往会非常薄弱。我见过不少 AI 生成的测试断言只是一个函数没有报错至于函数返回什么、业务结果是否符合预期完全没验证。问题就出在这里AI Agent 需要一个边界而 BDD 的 Feature 场景就是这个边界。场景里写清楚了“给定什么条件、执行什么动作、应该看到什么结果”AI 生成的步骤定义和断言就有一个明确的目标而不是自由发挥。这时候 Yadda 的价值就体现出来了它把场景文本和步骤函数绑定起来。AI 可以负责把需求转成 Feature 草稿甚至生成一部分步骤定义但最终验证标准来自场景本身。换句话说BDD 在 AI Agent 时代不是过时而是变成了需求契约。没有契约AI 生成得越快测试越容易变成自说自话。1.3 和 Cucumber 的侧重点不同Yadda 经常拿来和 Cucumber 对比。Cucumber 工程化程度高有配套的 CLI、标签机制和生态适合大团队标准化推进。Yadda 更灵活适合已经有自己的测试框架、只想引入 Gherkin 解析和步骤执行的部分。做 AI 应用开发时尤其是智能体调用工具、回调、状态流转这类逻辑Yadda 的轻量特性会方便很多。它不强制你必须用哪一套测试运行器这让 AI 生成的代码更容易被收拢到一个统一入口里验证。2. 跑通 Yadda 需要的最小环境与依赖2.1 环境要求Yadda 是纯 JavaScript 库没有编译步骤没有原生扩展也不需要 GPU。理论上只要你的 Node.js 能跑起来它基本就能跑。我的建议是至少使用当前还在维护的 LTS 版本因为旧版本 Node 在网络请求、异步处理、模块加载这些基础能力上差异不小容易让问题看起来像 Yadda 报错实际是环境太老。你还需要一个测试运行器或者至少能执行 JavaScript 脚本的方式。Mocha、Jest、Vitest 都可以。如果不想引入额外框架直接用 Node 的脚本入口也没问题。断言库可以用 Node 内置的assert也可以用 Chai。Yadda 本身不做断言所以断言库看个人习惯。真正影响运行环境的往往不是 Yadda而是被测系统。比如你的 BDD 场景要调用真实数据库、第三方 API、AI Agent 的服务接口那这些资源才是瓶颈。如果只是先验证 Yadda 本身完全可以只写内存里的逻辑。2.2 安装步骤我习惯先建一个干净目录再初始化项目mkdir yadda-bdd-demo cd yadda-bdd-demo npm init -y npm install yadda npm install -D mocha chai如果你不想用 Mocha可以只装yadda然后用 Node 直接执行脚本npm install yadda这里不要急着一次装一堆依赖。先跑通最小场景再根据实际需要加 API 客户端、数据库驱动、报告生成器排查问题时范围会更小。2.3 固定目录结构目录结构不必复杂但一定要固定。如果后续要接 AI 生成内容或者接 CI固定的目录比“灵活但散乱”的目录可靠得多。features/ login.feature steps/ login.steps.js test/ run.yadda.jsfeatures放 Gherkin 文件steps放步骤定义test放执行入口。这个结构不是 Yadda 硬性要求的它只要求你能拿到文本并解析。但我见过很多团队在 AI 生成代码后文件散落在各个目录最后找不到哪个步骤对应哪个场景代价很高。固定目录之后AI 生成工具也好、人工排查也好都能按路径快速定位。3. 一个最小 BDD 用例从 Gherkin 到步骤定义到执行3.1 先写一个登录场景不接真实服务先写一个最简单的用户登录场景目的是把整条链路跑通。新建features/login.featureFeature: 用户登录 Scenario: 正常登录 Given a user named alice When I login as alice Then I should see welcome这份文件同时服务于人和机器。产品经理看到的是业务场景测试看到的是验收点Yadda 看到的是步骤序列。场景里不需要写代码细节也不需要写数据库字段只写行为结果。3.2 步骤定义怎么组织新建steps/login.steps.js把每一句话绑定到一个 JavaScript 函数const assert require(chai).assert; const { Yadda, localisation } require(yadda); const English localisation.English; const library English.library() .given(a user named $name, function (name, done) { this.user { name }; done(); }) .when(I login as $name, function (name, done) { this.loginResult this.user this.user.name name ? welcome : denied; done(); }) .then(I should see $message, function (message, done) { assert.equal(this.loginResult, message); done(); }); const yadda new Yadda.Yadda(library); module.exports { yadda, library };这里的关键是参数捕捉。$name会匹配场景里对应的单词$message匹配另一段内容。步骤函数里第一个参数是捕捉到的值最后一个参数是done回调。如果你的业务里有异步操作比如请求接口或者查数据库就在异步操作完成后调用done()。如果使用 Promise 风格也可以返回 Promise具体以你安装的 Yadda 版本支持方式为准。这里容易忽略一个点this上下文。Yadda 默认会让多个步骤共享一个上下文对象所以你在 Given 里设置this.user在 When 里能读出来。不要把状态都写在全局变量里否则批量跑场景时彼此干扰。3.3 执行器新建test/run.yadda.jsconst { yadda } require(../steps/login.steps); const steps [ given a user named alice, when I login as alice, then I should see welcome ]; let index 0; function runNext() { if (index steps.length) { console.log(All steps passed); return; } const step steps[index]; yadda.runStep(step, (err) { if (err) { console.error(Step failed:, step); console.error(err.message); process.exit(1); } index 1; runNext(); }); } runNext();这段代码演示的是“把场景拆成步骤文本逐条跑”的流程。实际项目中你更可能直接解析完整的 Feature 文件让 Yadda 自己读取场景里的步骤。但我建议第一次测试时先用这种最朴素的方式因为一旦有问题你立刻能看出是哪一步跑失败了。注意步骤文本里的动词前缀。given、when、then对应步骤定义里的同名前缀。Yadda 的本地化支持能识别这些关键词大小写通常不敏感。如果写成英文需要和库文件里的文本严格对应少一个空格都会匹配失败。3.4 验证结果执行node test/run.yadda.js正常结果是在控制台看到每一步顺利执行最后输出All steps passed。如果把then里的断言改成不匹配的内容就会看到断言错误并且日志里明确显示是哪一步失败。先跑通这一段再考虑接真实登录接口。不要一开始就把数据库、文件系统、外部 API 全塞进去那样报错时你很难分清楚是 Yadda 的问题、断言库的问题还是被测服务的问题。4. AI Agent 辅助写 BDD提示词、审查和自动化衔接4.1 AI 能帮到什么程度讨论 AI 编程和 AI 测试时很多人会把“生成代码”和“工程质量”混在一起。AI 非常适合生成 Feature 草稿、Mock 数据、步骤定义骨架它可以快速补出一个场景里最容易重复的部分。但 AI 不应该替你决定“什么才是正确的业务结果”。我从实践里得到的判断标准是这样的如果 AI 生成的步骤定义里断言部分来自它自己构造的假数据那这条测试基本没有验收价值。真正合适的用法是AI 从需求描述里提炼出 Given-When-Then 结构然后由人确认行为结果再让 AI 去填充步骤代码。这样 AI 做的是翻译和骨架工作验收标准仍然由人控制。4.2 一个可复用的提示词模板如果你经常让 AI 生成 BDD 用例可以准备一个固定提示词模板。下面这个模板可以直接用重点是约束输出格式你是 BDD 测试助手。请根据以下需求描述生成 Gherkin 格式的 Feature 场景 1. 使用 Given-When-Then 结构。 2. 每个场景只描述一个行为结果。 3. 参数用英文单词表示不要包含数据库表名或接口路径等实现细节。 4. 同时生成对应的步骤定义骨架但断言部分保留 TODO不替我写具体预期。 5. 不生成任何绕过系统限制、绕过权限校验或突破审核逻辑的测试用例。 需求描述 在这里粘贴需求模板里有两点很关键。一是“每个场景只描述一个行为结果”这能防止 AI 生成一个步骤链特别长、什么都想验证的巨型场景。二是“断言部分保留 TODO”这样你必须在最后补上真实预期而不是让 AI 自问自答。4.3 人工审查必须看的三个点AI 生成的 Feature 文本和步骤定义我会按三个顺序来审第一场景是不是从用户行为出发。如果场景里全是接口路径、数据库字段、变量名这个场景就写失败了。BDD 场景应该可以被业务人员读懂。第二Given-When-Then 是否完整。很多人写的场景里只有 When 和 Then没有前置条件导致测试在固定环境里能跑换个环境就失败。缺 Given 是第一批不稳定用例的常见原因。第三断言是否验证了真实结果。AI 经常生成“函数没有抛异常”这种弱断言。对应到登录场景里弱断言就是不检查返回值是否变成了 welcome。检查断言时我会看它抓的是实际业务输出还是自己构造的数据。4.4 与 AI Agent 应用开发的衔接当被测对象本身是一个 AI Agent 时Yadda 也很有用。比如你有一个 Agent用户提问后它会调用工具再把结果组织成回复。你可以用 Feature 描述这类链路Feature: 工具调用 Scenario: 查询不存在的地点 Given user asks where Beijing Station is When the agent calls the location tool Then the tool returns no result And the agent responds with a retry hint这种场景把 Agent 的输入、工具返回、最终回复串成一条可执行链路。AI Agent 的响应有随机性所以步骤定义里应该对结果做模糊匹配比如“回复中包含重试提示”而不是匹配一整段话。这是我在测试智能体时比较深的体会BDD 场景不能写得比 Agent 自己还死板否则会频繁误报。5. 批量场景、超时重试与 CI 集成5.1 批量场景和标签过滤单场景跑通之后你自然会想把多个 Feature 文件批量执行。Yadda 本身是一个解析和执行库批量执行时一般由外层测试框架负责组织和过滤。你也可以自己遍历features目录下的所有.feature文件逐个解析、逐个执行。我的建议是先用目录命名和文件名做分片不要过度设计标签系统。比如按业务模块建features/login、features/payment再在外层入口里选择跑哪个目录。原因是简单、可预测AI 生成文件时也不容易搞乱。如果未来场景数量很大再用测试框架提供的 grep 能力按场景名过滤。比如 Mocha 支持--grepJest 支持-t。不要在一开始就依赖标签依赖因为标签写错的时候场景会在静默中被跳过你甚至不会意识到少跑了测试。5.2 超时与重试策略接真实服务之后第一步要面对的就是超时。Yadda 的每个步骤都执行 JavaScript 函数如果步骤里发了一个 HTTP 请求接口响应 30 秒你的整体测试就会很难受。我一般会先在每一步里控制总的等待时间同时给外层脚本一个总超时避免某一步卡住后整个任务永远不结束。重试要区分两种环境抖动导致的失败和业务逻辑失败。网络抖动可以用重试解决断言失败则不应该盲目重试。在 CI 里设置“失败后重跑一次”时我会同时把失败日志原样保留不覆盖上一次结果。这样才能在重试通过后还能回头分析第一次为什么失败。如果你在跑 AI Agent 相关测试重试策略更要谨慎。Agent 的回复有随机性第一次触发限流、第二次成功这种情况重试合理。如果是业务逻辑本身有 Bug重试一百次也过不了反而会掩盖问题。5.3 接入 CI 的通用流程接入 CI 不需要理解所有 Yadda 细节只需要把执行步骤固定下来。一个通用流程是安装依赖。启动被测服务或者启动 Mock 服务。运行 Yadda 用例输出 JSON 或 JUnit 报告。上传报告产物方便失败时查看。如果你的 CI 是 GitHub Actions、GitLab CI 或其他平台思路都类似。关键是让“运行测试”这一步成为流水线上不可跳过且必须验证结果的任务。不要把它放在一个手动触发的角落任务里否则没人会注意到用例开始失败。6. 常见报错与排查顺序6.1 场景没被执行如果控制台里什么都没发生或者用例数量为 0优先检查文件路径。Feature 文件是否真的存在于你遍历的目录里文件名后缀是否正确解析时是不是传了空内容这种问题看起来像是 Yadda 的锅实际经常是路径写错了或者目录大小写和系统不对应。排查时先打印一次“读取到的文件列表”再进入执行环节。6.2 步骤定义找不到报错信息里如果出现类似 “undefined step” 或者说找不到匹配的步骤定义优先检查两点。第一步骤文本里的动词前缀和步骤定义里的前缀是否一致。第二文本匹配是否完全一致空格、引号、大小写都会影响匹配。还有一个常见坑步骤定义在 A 文件里但执行器里加载的是 B 文件里的yadda实例。检查模块引用路径尤其是目录结构调整后旧的相对路径很可能还在生效。6.3 异步回调卡住步骤执行到一半永远不结束大多是done没有被调用或者在错误路径里没有调用。排查时去代码里看所有done的出口正常结束要调用异常分支也要调用。如果用了 Promise 风格检查是否把 Promise 返回给了 Yadda。不要在 Promise 内部自己吞掉错误。异步测试卡住的另一个常见原因是无限重试和循环重试逻辑里忘记加最大次数也会造成测试一直挂着。6.4 环境相关报错模块加载失败时先确认node_modules是否完整是否用了和项目不匹配的包管理器。ES Module 和 CommonJS 混用时require和import很容易出错。Yadda 本身支持在 CommonJS 项目里使用如果你的项目是type: module需要按官方文档调整加载方式。遇到环境问题时我的排查顺序是先看日志和现象再看输入文件有没有变化然后检查依赖版本和系统环境最后才怀疑 Yadda 本身的实现。很多问题看起来像工具不支持实际是数据、路径、权限或者 Node 版本差异。7. 边界、误区和我的建议7.1 不要把 BDD 变成“用英文写一遍代码”最需要警惕的反模式是把 Feature 场景写成像把代码翻译成自然语言。比如“Given the function returns a number”这种描述没有任何业务含义产品经理看不懂测试执行也像在绕圈子。BDD 场景应该描述“用户做了什么、对外呈现什么结果”而不是“代码内部哪一行调用了什么”。这一点在 AI 生成场景时特别容易失守因为模型会倾向于从代码库里提取变量名和方法名。人工审查时看到这类描述就要提醒自己把场景拉回业务层面。7.2 低配置环境也能试Yadda 本身不重内存占用和 CPU 需求都不高。没有 GPU、没有独立测试服务器完全可以在本地笔记本上把场景跑起来。真正需要资源评估的是被测系统如果你要测试完整的 AI 模型推理那瓶颈在模型服务上如果只测 Agent 的调度逻辑用 Mock 数据也能验证。批量任务不要一上来就开最大并发。先跑一条场景确认输入、输出和日志正常再逐步增加。并发生成测试数据时注意数据库唯一索引和文件命名冲突这些问题在单条任务里根本看不见。7.3 我的最终建议回到 Yadda 3.0.0 本身我的判断是版本号不是重点重点是它把 BDD 拆成了解析、步骤注册、执行这三件独立的事这在 AI Agent 大量参与开发的环境里反而是优势。AI 生成 Feature、生成步骤骨架、按场景执行回归每一步都能被单独替换和审查。如果你想试就从最简登录场景开始先跑通单条用例再加异步逻辑再接入真实服务最后放到 CI 里。整个过程不需要大而全的设计只需要一条稳定的通道业务场景能变成可执行测试AI 生成的内容能被人工审查失败任务能被快速定位。能做到这三点BDD 在 AI Agent 时代就还有非常实际的价值。