Node Tap 单元测试入门指南
Node Tap 是面向现代 Node.js 的测试运行器,原生输出 TAP 格式。本文讲解 Tap 的环境搭建、编写与运行测试、用例过滤、源码内嵌测试与 Mock 能力。
本文依据官方文档整理,未执行运行验证或性能基准。代码片段展示局部用法,业务函数、数据和环境需按项目补齐;版本与配置以所引文档为准。
直接回答:Node Tap(tap)是一个Node.js 测试运行器,提供断言与TAP输出、输出遵循 TAP(Test Anything Protocol)标准格式,前端与后端 JavaScript 项目都适用。
Tap 的特点
- TAP 输出:标准化的测试输出协议,天然适合 CI 解析与展示;
- 零配置但有料:断言、内置覆盖率收集(实现随 tap 版本变化,不固定等同 c8)、Mock 一应俱全;
- 每个文件独立进程:测试文件之间天然隔离,不怕全局状态污染。
搭建环境
mkdir node-tap-demo && cd node-tap-demo
npm init -y
npm pkg set type=module
npm install --save-dev tap
建一个被测模块 math.js:
export function add(a, b) {
return a + b;
}
第一条测试
Tap 的测试文件即普通脚本,test/math.test.js:
import t from "tap";
import { add } from "../math.js";
t.test("add 函数", async (t) => {
t.equal(add(1, 2), 3, "1 + 2 = 3");
t.equal(add(-1, 1), 0, "-1 + 1 = 0");
});
npx tap 一次跑完所有测试并附赠覆盖率报告。每个断言自带说明文字,失败时输出一目了然。
常用断言:t.equal(严格相等)、t.same(深比较)、t.match(部分匹配对象)、t.throws(抛错)、t.ok(真值)。
运行与过滤
npx tap test/math.test.js:跑单个文件;npx tap --grep="add":按名称过滤用例;npx tap --watch:文件变动自动重跑。
源码内嵌测试
可以通过项目自定义开关在源码中放局部自测,但这不是 tap 自动收集的特殊语法:
// math.js
export function add(a, b) {
return a + b;
}
// APP_SELF_TEST 是本项目约定的开关,不是 tap 内置环境变量
if (process.env.APP_SELF_TEST === '1') {
const { default: t } = await import('tap');
t.equal(add(2, 2), 4);
}
可用 APP_SELF_TEST=1 node math.js 显式执行;生产启动不要设置该开关。tap 不会因此自动发现 math.js,也不自动剔除这些代码;常规项目建议保留独立测试目录。
Mock 能力
Tap 内置 t.mockImport()(ESM 场景)可以在加载模块时替换其依赖:
const { getUser } = await t.mockImport("../user-service.js", {
"../db.js": { query: async () => [{ id: 1, name: "Ada" }] },
});
t.same(await getUser(1), { id: 1, name: "Ada" });
不需要额外装 sinon 之类,常规依赖替换开箱即用。
常见问题(FAQ)
Q:TAP 格式有什么好处?
A:它是跨语言的测试输出标准,任何能理解 TAP 的 CI、报告器都能直接消费,工具链整合成本低。
Q:Tap 和 Node 内置 test runner 比如何?
A:内置 runner 胜在零依赖;Tap 胜在生态成熟、断言丰富、覆盖率内置。想要"装了就能用全家桶"选 Tap,想极简选内置。
Q:为什么我的测试进程不退?
A:通常是有未关闭的句柄(数据库连接、定时器)。Tap 对此很敏感并会明确提示,按提示找到泄漏点关掉即可。
官方参考
资料核对日期:2026-09-29。