Deno 如何为新 CLI 行为编写 spec 测试?
【免费下载链接】denoA modern runtime for JavaScript and TypeScript.项目地址: https://gitcode.com/GitHub_Trending/de/deno
当你给 Deno 加了新 flag、改了子命令行为、或者调整了报错信息之后,需要一个能从命令行观察到结果、并对输出做断言的集成测试。Deno 的主集成测试就是 spec 测试:它位于tests/specs/,每个测试目录里的__test__.jsonc描述一次或多次deno调用,框架会执行这些调用、捕获输出,并与你写的期望值做匹配。只要改动可以从命令行观察到,就应该为它写一个 spec 测试(见 doc/testing.md)。
前提:能构建出本地的 deno 二进制
spec 测试执行的是编译出来的deno二进制,所以先按 CLAUDE.md 的 Quick Start 装好依赖(Rust、原生编译器、cmake、protobuf 等,完整前置见.github/CONTRIBUTING.md)并完成构建:
cargo build开发期快速迭代可以用cargo build --bin deno。
第一步:创建测试目录
在tests/specs/下建一个有描述性的目录。实际惯例是按命令归类到类别目录下,例如tests/specs/eval/eval_basic/。测试名就是目录名,目录内放:
tests/specs/eval/eval_basic/ __test__.jsonc main.out真实的极简例子 eval_basic:
{ "args": "eval console.log(\"hello\")", "output": "main.out" }同目录的main.out内容是hello,即期望输出的断言文件。测试目录里按需放被测命令用到的输入文件(如main.ts)。
第二步:编写test.jsonc
__test__.jsonc的完整字段定义在 tests/specs/schema.json,支持三种结构(见 tests/specs/README.md):
- 单步:
args、output直接写在顶层(即上面的例子)。 - 多步:
steps数组,每步一个对象:
{ "tempDir": true, "steps": [ { "args": "cache main.ts", "output": "cache.out" }, { "args": "run main.ts", "output": "error.out", "exitCode": 1 } ] }- 同一目录跑多个命名测试:
tests对象,每个键是一个测试名。
各步骤常用的字段(schema 与 README 中均有定义):
args:字符串(按空白拆分)或参数数组,即deno后面的部分;output:期望输出的.out文件路径,或内联的匹配文本;exitCode:期望退出码,例如 env_vars_documented 里对deno --help=full断言"exitCode": 0;if:按平台选择性执行,如"linux"、"windows"、"unix"、"mac";flaky:步骤最多重复 3 次直到成功;envs:为该测试设置的环境变量;- 顶层
tempDir: true:把非测试文件复制到临时目录并在其中执行,适合会生成node_modules之类产物的测试。
多步/多测试结构还支持timeout(每个步骤的超时,秒,默认 300)、repeat、base等字段,详见 tests/specs/schema.json。
输出断言的匹配语言
期望输出支持一套小的匹配语法,字面字符表示精确匹配,特殊标记有(tests/specs/README.md、CLAUDE.md):
[WILDCARD]:匹配任意个任意字符,可跨行,等价于正则的.*;[WILDLINE]:匹配当前行内任意个任意字符,到行尾为止;[WILDCHAR]:匹配下一个字符;[WILDCHARS(5)]:匹配接下来的 5 个任意字符;[UNORDERED_START]…[UNORDERED_END]:中间的行按任意顺序匹配,适合非确定性输出;[# 示例]:行内注释,以[#开始、]结束。
.out文件示例(来自 CLAUDE.md,示例结果):
Check file://[WILDCARD]/main.ts [WILDCARD] Successfully compiled [WILDLINE]第三步:运行并验证
仓库根目录的./x脚本封装了常用测试入口(实现见 tools/x.ts):
# 按名称子串跑 spec 测试(底层是 cargo test -p specs_tests --test specs -- <filter>) ./x test-spec eval_basic # 列出所有可用的 spec 测试 ./x test-spec --list也可以用 cargo 直接按测试路径过滤(tests/specs/README.md):
# 精确到 类别::测试名 cargo test specs::eval::eval_basic # 查看所有测试的输出(注意:测试会串行执行而不是并行) cargo test eval_basic -- --no-capture判断标准很直接:命令以 0 退出、测试通过,说明输出与期望值匹配;失败时先查看测试输出与期望的差异,然后:
- 输出格式是被你有意改过的,更新对应的
.out文件; - 输出里包含非确定性内容(路径、时间戳、乱序行),改用
[WILDCARD]、[WILDLINE]或[UNORDERED_START]/[UNORDERED_END]放宽匹配。
这两条来自 CLAUDE.md 的 Test Failures 部分。
可选:编辑器里获得 schema 自动补全
把下面配置加入本地.vscode/settings.json(tests/specs/README.md 给出的配置,url相对于仓库根目录):
{ "json.schemas": [{ "fileMatch": ["__test__.jsonc"], "url": "./tests/specs/schema.json" }] }提交前
spec 测试本身没有独立的 lint 步骤,但按 doc/testing.md 的要求,推送前运行tools/format.js和相应的tools/lint.js调用(只改了 JS/TS 时用tools/lint.js --js)。CI 会在 PR 上跑完整的 spec 套件,所以本地能过./x test-spec <name>不代表 CI 一定过,跨平台差异的行为要用if字段显式区分。
【免费下载链接】denoA modern runtime for JavaScript and TypeScript.项目地址: https://gitcode.com/GitHub_Trending/de/deno
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考