- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS模块
- module/esm ECMAScript模块
- module/package 包模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
Node.js v20.2.0 文档
- Node.js v20.2.0
-
►
目录
- 测试运行器
- 子测试
- 跳过测试
describe
/it
语法only
测试- 按名称过滤测试
- 无关的异步活动
- 监视模式
- 从命令行运行测试
- 收集代码覆盖率
- 模拟
- 测试报告器
run([options])
test([name][, options][, fn])
test.skip([name][, options][, fn])
test.todo([name][, options][, fn])
test.only([name][, options][, fn])
describe([name][, options][, fn])
describe.skip([name][, options][, fn])
describe.todo([name][, options][, fn])
describe.only([name][, options][, fn])
it([name][, options][, fn])
it.skip([name][, options][, fn])
it.todo([name][, options][, fn])
it.only([name][, options][, fn])
before([fn][, options])
after([fn][, options])
beforeEach([fn][, options])
afterEach([fn][, options])
- 类:
MockFunctionContext
- 类:
MockTracker
- 类:
TestsStream
- 类:
TestContext
context.before([fn][, options])
context.beforeEach([fn][, options])
context.after([fn][, options])
context.afterEach([fn][, options])
context.diagnostic(message)
context.name
context.runOnly(shouldRunOnlyTests)
context.signal
context.skip([message])
context.todo([message])
context.test([name][, options][, fn])
- 类:
SuiteContext
- 测试运行器
-
►
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS模块
- module/esm ECMAScript模块
- module/package 包模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
- ► 其他版本
- 云服务器
目录
- 测试运行器
- 子测试
- 跳过测试
describe
/it
语法only
测试- 按名称过滤测试
- 无关的异步活动
- 监视模式
- 从命令行运行测试
- 收集代码覆盖率
- 模拟
- 测试报告器
run([options])
test([name][, options][, fn])
test.skip([name][, options][, fn])
test.todo([name][, options][, fn])
test.only([name][, options][, fn])
describe([name][, options][, fn])
describe.skip([name][, options][, fn])
describe.todo([name][, options][, fn])
describe.only([name][, options][, fn])
it([name][, options][, fn])
it.skip([name][, options][, fn])
it.todo([name][, options][, fn])
it.only([name][, options][, fn])
before([fn][, options])
after([fn][, options])
beforeEach([fn][, options])
afterEach([fn][, options])
- 类:
MockFunctionContext
- 类:
MockTracker
- 类:
TestsStream
- 类:
TestContext
context.before([fn][, options])
context.beforeEach([fn][, options])
context.after([fn][, options])
context.afterEach([fn][, options])
context.diagnostic(message)
context.name
context.runOnly(shouldRunOnlyTests)
context.signal
context.skip([message])
context.todo([message])
context.test([name][, options][, fn])
- 类:
SuiteContext
测试运行器#
源代码: lib/test.js
node:test
模块有助于创建 JavaScript 测试。
要访问它:
import test from 'node:test';
const test = require('node:test');
此模块仅在 node:
协议下可用。 以下将不起作用:
import test from 'test';
const test = require('test');
通过 test
模块创建的测试由单个函数组成,该函数以三种方式之一进行处理:
- 同步的函数,如果抛出异常则认为失败,否则认为通过。
- 返回
Promise
的函数,如果Promise
拒绝,则认为该函数失败,如果Promise
解决,则认为该函数通过。 - 接收回调函数的函数。 如果回调接收到任何真值作为其第一个参数,则认为测试失败。 如果非真值作为第一个参数传给回调,则认为测试通过。 如果测试函数接收到回调函数并且还返回
Promise
,则测试将失败。
以下示例说明了如何使用 test
模块编写测试。
test('synchronous passing test', (t) => {
// This test passes because it does not throw an exception.
assert.strictEqual(1, 1);
});
test('synchronous failing test', (t) => {
// This test fails because it throws an exception.
assert.strictEqual(1, 2);
});
test('asynchronous passing test', async (t) => {
// This test passes because the Promise returned by the async
// function is not rejected.
assert.strictEqual(1, 1);
});
test('asynchronous failing test', async (t) => {
// This test fails because the Promise returned by the async
// function is rejected.
assert.strictEqual(1, 2);
});
test('failing test using Promises', (t) => {
// Promises can be used directly as well.
return new Promise((resolve, reject) => {
setImmediate(() => {
reject(new Error('this will cause the test to fail'));
});
});
});
test('callback passing test', (t, done) => {
// done() is the callback function. When the setImmediate() runs, it invokes
// done() with no arguments.
setImmediate(done);
});
test('callback failing test', (t, done) => {
// When the setImmediate() runs, done() is invoked with an Error object and
// the test fails.
setImmediate(() => {
done(new Error('callback failure'));
});
});
如果任何测试失败,则进程退出代码设置为 1
。
子测试#
测试上下文的 test()
方法允许创建子测试。 此方法的行为与顶层 test()
函数相同。 以下示例演示了如何创建具有两个子测试的顶层测试。
test('top level test', async (t) => {
await t.test('subtest 1', (t) => {
assert.strictEqual(1, 1);
});
await t.test('subtest 2', (t) => {
assert.strictEqual(2, 2);
});
});
在本示例中,await
用于确保两个子测试均已完成。
这是必要的,因为父测试不会等待子测试完成。 当父测试完成时仍然未完成的任何子测试将被取消并视为失败。 任何子测试失败都会导致父测试失败。
跳过测试#
通过将 skip
选项传递给测试,或通过调用测试上下文的 skip()
方法,可以跳过单个测试,如下例所示。
// The skip option is used, but no message is provided.
test('skip option', { skip: true }, (t) => {
// This code is never executed.
});
// The skip option is used, and a message is provided.
test('skip option with message', { skip: 'this is skipped' }, (t) => {
// This code is never executed.
});
test('skip() method', (t) => {
// Make sure to return here as well if the test contains additional logic.
t.skip();
});
test('skip() method with message', (t) => {
// Make sure to return here as well if the test contains additional logic.
t.skip('this is skipped');
});
describe
/it
语法#
运行测试也可以使用 describe
来声明套件和 it
来声明测试。
套件用于将相关测试组织和分组在一起。
it
是 test()
的简写。
describe('A thing', () => {
it('should work', () => {
assert.strictEqual(1, 1);
});
it('should be ok', () => {
assert.strictEqual(2, 2);
});
describe('a nested thing', () => {
it('should work', () => {
assert.strictEqual(3, 3);
});
});
});
describe
和 it
是从 node:test
模块导入的。
import { describe, it } from 'node:test';
const { describe, it } = require('node:test');
only
测试#
如果 Node.js 使用 --test-only
命令行选项启动,则可以通过将 only
选项传给应该运行的测试来跳过除选定子集之外的所有顶层测试。 当运行带有 only
选项集的测试时,所有子测试也会运行。 测试上下文的 runOnly()
方法可用于在子测试级别实现相同的行为。
// Assume Node.js is run with the --test-only command-line option.
// The 'only' option is set, so this test is run.
test('this test is run', { only: true }, async (t) => {
// Within this test, all subtests are run by default.
await t.test('running subtest');
// The test context can be updated to run subtests with the 'only' option.
t.runOnly(true);
await t.test('this subtest is now skipped');
await t.test('this subtest is run', { only: true });
// Switch the context back to execute all tests.
t.runOnly(false);
await t.test('this subtest is now run');
// Explicitly do not run these tests.
await t.test('skipped subtest 3', { only: false });
await t.test('skipped subtest 4', { skip: true });
});
// The 'only' option is not set, so this test is skipped.
test('this test is not run', () => {
// This code is not run.
throw new Error('fail');
});
按名称过滤测试#
--test-name-pattern
命令行选项可用于仅运行名称与提供的模式匹配的测试。 测试名称模式被解释为 JavaScript 正则表达式。 可以多次指定 --test-name-pattern
选项以运行嵌套测试。 对于执行的每个测试,也会运行任何相应的测试钩子,例如 beforeEach()
。
给定以下测试文件,使用 --test-name-pattern="test [1-3]"
选项启动 Node.js 将导致测试运行程序执行 test 1
、test 2
和 test 3
。 如果 test 1
不匹配测试名称模式,那么它的子测试将不会执行,尽管匹配模式。 同一组测试也可以通过多次传递 --test-name-pattern
来执行(例如 --test-name-pattern="test 1"
、--test-name-pattern="test 2"
等)。
test('test 1', async (t) => {
await t.test('test 2');
await t.test('test 3');
});
test('Test 4', async (t) => {
await t.test('Test 5');
await t.test('test 6');
});
也可以使用正则表达式字面指定测试名称模式。 这允许使用正则表达式标志。 在前面的示例中,以 --test-name-pattern="/test [4-5]/i"
开头的 Node.js 将匹配 Test 4
和 Test 5
,因为该模式不区分大小写。
测试名称模式不会更改测试运行程序执行的文件集。
无关的异步活动#
一旦测试函数完成执行,将在保持测试顺序的同时尽快报告结果。 但是,测试函数可能会生成比测试本身寿命更长的异步活动。 测试运行器处理此类活动,但不会延迟报告测试结果以适应它。
在下面的示例中,测试完成时仍然有两个 setImmediate()
操作未完成。 第一个 setImmediate()
尝试创建新的子测试。 因为父测试已经完成并输出结果,所以新的子测试立即标记为失败,稍后报告给 <TestsStream>。
第二个 setImmediate()
创建了 uncaughtException
事件。
源自已完成测试的 uncaughtException
和 unhandledRejection
事件被 test
模块标记为失败,并由 <TestsStream> 在顶层报告为诊断警告。
test('a test that creates asynchronous activity', (t) => {
setImmediate(() => {
t.test('subtest that is created too late', (t) => {
throw new Error('error1');
});
});
setImmediate(() => {
throw new Error('error2');
});
// The test finishes after this line.
});
监视模式#
Node.js 测试运行器支持通过传递 --watch
标志以监视模式运行:
node --test --watch
在监视模式下,测试运行器将监视测试文件及其依赖项的更改。 当检测到变化时,测试运行器将重新运行受变化影响的测试。 测试运行器将继续运行直到进程终止。
从命令行运行测试#
可以通过传入 --test
标志从命令行调用 Node.js 测试运行程序:
node --test
默认情况下,Node.js 将递归搜索当前目录以查找匹配特定命名约定的 JavaScript 源文件。 匹配文件作为测试文件执行。 有关预期测试文件命名约定和行为的更多信息,请参见 测试运行器执行模型 部分。
或者,可以提供一个或多个路径作为 Node.js 命令的最终参数,如下所示。
node --test test1.js test2.mjs custom_test_dir/
在本例中,测试运行程序将执行文件 test1.js
和 test2.mjs
。 测试运行器还将递归搜索 custom_test_dir/
目录以查找要执行的测试文件。
测试运行器执行模型#
当搜索要执行的测试文件时,测试运行器的行为如下:
- 执行用户显式提供的任何文件。
- 如果用户没有显式地指定任何路径,则递归搜索当前工作目录中指定的文件,如以下步骤所示。
- 除非用户显式地提供,否则跳过
node_modules
目录。 - 如果遇到名为
test
的目录,则测试运行程序将递归搜索所有.js
、.cjs
和.mjs
文件。 所有这些文件都被视为测试文件,不需要匹配下面详述的特定命名约定。 这是为了适应将所有测试放在单个test
目录中的项目。 - 在所有其他目录中,匹配以下模式的
.js
、.cjs
和.mjs
文件被视为测试文件:^test$
- 基本名称为字符串'test'
的文件。 示例:test.js
、test.cjs
、test.mjs
。^test-.+
- 基本名称以字符串'test-'
后跟一个或多个字符开头的文件。 示例:test-example.js
,test-another-example.mjs
。.+[\.\-\_]test$
- 基本名称以.test
、-test
或_test
结尾且前面有一个或多个字符的文件。 示例:example.test.js
、example-test.cjs
、example_test.mjs
。- Node.js 理解的其他文件类型,例如
.node
和.json
,不会由测试运行程序自动执行,但如果在命令行上显式地提供,则支持。
每个匹配的测试文件都在单独的子进程中执行。 如果子进程以退出代码 0 结束,则认为测试通过。
否则,认为测试失败。 测试文件必须是 Node.js 可执行文件,但不需要在内部使用 node:test
模块。
每个测试文件都像常规脚本一样执行。 也就是说,如果测试文件本身使用 node:test
来定义测试,则所有这些测试都将在单个应用程序线程中执行,而不管 test()
的 concurrency
选项的值如何。
收集代码覆盖率#
当 Node.js 以 --experimental-test-coverage
命令行标志启动时,代码覆盖率将被收集并在所有测试完成后报告统计信息。 如果使用 NODE_V8_COVERAGE
环境变量指定代码覆盖目录,则生成的 V8 覆盖文件写入该目录。 node_modules/
目录中的 Node.js 核心模块和文件未包含在覆盖率报告中。 如果启用覆盖,覆盖报告将通过 'test:coverage'
事件发送到任何 测试报告器。
可以使用以下注释语法在一系列行上禁用覆盖:
/* node:coverage disable */
if (anAlwaysFalseCondition) {
// Code in this branch will never be executed, but the lines are ignored for
// coverage purposes. All lines following the 'disable' comment are ignored
// until a corresponding 'enable' comment is encountered.
console.log('this is never executed');
}
/* node:coverage enable */
也可以针对指定行数禁用覆盖。 在指定的行数之后,将自动重新启用覆盖。 如果未明确提供行数,则忽略单行。
/* node:coverage ignore next */
if (anAlwaysFalseCondition) { console.log('this is never executed'); }
/* node:coverage ignore next 3 */
if (anAlwaysFalseCondition) {
console.log('this is never executed');
}
测试运行器的代码覆盖功能有以下限制,将在未来的 Node.js 版本中解决:
- 不支持源映射。
- 不支持从覆盖率报告中排除特定文件或目录。
模拟#
node:test
模块支持通过顶层 mock
对象在测试期间进行模拟。 以下示例创建了一个对将两个数字相加的函数的监视。 间谍随后被用来断言该函数已按预期调用。
import assert from 'node:assert';
import { mock, test } from 'node:test';
test('spies on a function', () => {
const sum = mock.fn((a, b) => {
return a + b;
});
assert.strictEqual(sum.mock.calls.length, 0);
assert.strictEqual(sum(3, 4), 7);
assert.strictEqual(sum.mock.calls.length, 1);
const call = sum.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3, 4]);
assert.strictEqual(call.result, 7);
assert.strictEqual(call.error, undefined);
// Reset the globally tracked mocks.
mock.reset();
});
'use strict';
const assert = require('node:assert');
const { mock, test } = require('node:test');
test('spies on a function', () => {
const sum = mock.fn((a, b) => {
return a + b;
});
assert.strictEqual(sum.mock.calls.length, 0);
assert.strictEqual(sum(3, 4), 7);
assert.strictEqual(sum.mock.calls.length, 1);
const call = sum.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3, 4]);
assert.strictEqual(call.result, 7);
assert.strictEqual(call.error, undefined);
// Reset the globally tracked mocks.
mock.reset();
});
相同的模拟功能也暴露在每个测试的 TestContext
对象上。 以下示例使用 TestContext
上公开的 API 创建对象方法的监听器。 通过测试上下文进行模拟的好处是,测试运行器将在测试完成后自动恢复所有模拟功能。
test('spies on an object method', (t) => {
const number = {
value: 5,
add(a) {
return this.value + a;
},
};
t.mock.method(number, 'add');
assert.strictEqual(number.add.mock.calls.length, 0);
assert.strictEqual(number.add(3), 8);
assert.strictEqual(number.add.mock.calls.length, 1);
const call = number.add.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3]);
assert.strictEqual(call.result, 8);
assert.strictEqual(call.target, undefined);
assert.strictEqual(call.this, number);
});
测试报告器#
node:test
模块支持传递 --test-reporter
标志,以便测试运行器使用特定的报告程序。
支持以下内置报告器:
-
tap
tap
报告器以 TAP 格式输出测试结果。 -
spec
spec
报告器以人类可读的格式输出测试结果。 -
dot
dot
报告器以紧凑格式输出测试结果,其中每个通过的测试用.
表示,每个失败的测试用X
表示。
当 stdout
为 TTY 时,默认使用 spec
报告器。
否则,默认使用 tap
报告器。
这些报告器的确切输出可能会因 Node.js 版本而异,不应以编程方式依赖。 如果需要以编程方式访问测试运行程序的输出,请使用 <TestsStream> 触发的事件。
报告器可通过 node:test/reporters
模块获得:
import { tap, spec, dot } from 'node:test/reporters';
const { tap, spec, dot } = require('node:test/reporters');
自定义报告器#
--test-reporter
可用于指定自定义报告程序的路径。
自定义报告器是一个导出 stream.compose 接受的值的模块。
报告者应该转换 <TestsStream> 触发的事件
使用 <stream.Transform> 的自定义报告器示例:
import { Transform } from 'node:stream';
const customReporter = new Transform({
writableObjectMode: true,
transform(event, encoding, callback) {
switch (event.type) {
case 'test:start':
callback(null, `test ${event.data.name} started`);
break;
case 'test:pass':
callback(null, `test ${event.data.name} passed`);
break;
case 'test:fail':
callback(null, `test ${event.data.name} failed`);
break;
case 'test:plan':
callback(null, 'test plan');
break;
case 'test:diagnostic':
callback(null, event.data.message);
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
callback(null, `total line count: ${totalLineCount}\n`);
break;
}
}
},
});
export default customReporter;
const { Transform } = require('node:stream');
const customReporter = new Transform({
writableObjectMode: true,
transform(event, encoding, callback) {
switch (event.type) {
case 'test:start':
callback(null, `test ${event.data.name} started`);
break;
case 'test:pass':
callback(null, `test ${event.data.name} passed`);
break;
case 'test:fail':
callback(null, `test ${event.data.name} failed`);
break;
case 'test:plan':
callback(null, 'test plan');
break;
case 'test:diagnostic':
callback(null, event.data.message);
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
callback(null, `total line count: ${totalLineCount}\n`);
break;
}
}
},
});
module.exports = customReporter;
使用生成器函数的自定义报告器示例:
export default async function * customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:start':
yield `test ${event.data.name} started\n`;
break;
case 'test:pass':
yield `test ${event.data.name} passed\n`;
break;
case 'test:fail':
yield `test ${event.data.name} failed\n`;
break;
case 'test:plan':
yield 'test plan';
break;
case 'test:diagnostic':
yield `${event.data.message}\n`;
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
yield `total line count: ${totalLineCount}\n`;
break;
}
}
}
}
module.exports = async function * customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:start':
yield `test ${event.data.name} started\n`;
break;
case 'test:pass':
yield `test ${event.data.name} passed\n`;
break;
case 'test:fail':
yield `test ${event.data.name} failed\n`;
break;
case 'test:plan':
yield 'test plan\n';
break;
case 'test:diagnostic':
yield `${event.data.message}\n`;
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
yield `total line count: ${totalLineCount}\n`;
break;
}
}
}
};
提供给 --test-reporter
的值应该是一个类似于 JavaScript 代码中的 import()
中使用的字符串,或者提供给 --import
的值。
多报告器#
可以多次指定 --test-reporter
标志,以多种格式报告测试结果。 在这种情况下,需要使用 --test-reporter-destination
为每个报告者指定目的地。
目标可以是 stdout
、stderr
或文件路径。
报告器和目的地根据指定的顺序配对。
在下面的例子中,spec
报告器将输出到 stdout
,dot
报告器将输出到 file.txt
:
node --test-reporter=spec --test-reporter=dot --test-reporter-destination=stdout --test-reporter-destination=file.txt
当指定单个报告者时,目的地将默认为 stdout
,除非明确提供目的地。
run([options])
#
options
<Object> 运行测试的配置选项。 支持以下属性:concurrency
<number> | <boolean> 如果提供了一个数字,那么许多测试进程将并行运行,其中每个进程对应一个测试文件。 如果是true
,它将并行运行os.availableParallelism() - 1
个测试文件。 如果是false
,它一次只会运行一个测试文件。 默认值:false
。files
: <Array> 包含要运行的文件列表的数组。 默认匹配来自 测试运行器执行模型 的文件。setup
<Function> 接受TestsStream
实例并可用于在运行任何测试之前设置监听器的函数。 默认值:undefined
。signal
<AbortSignal> 允许中止正在进行的测试执行。timeout
<number> 测试执行将在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。inspectPort
<number> | <Function> 设置测试子进程的检查器端口。 这可以是数字,也可以是不带参数并返回数字的函数。 如果提供了一个空值,每个进程都有自己的端口,从主进程的process.debugPort
递增。 默认值:undefined
。testNamePatterns
<string> | <RegExp> | <Array> 一个字符串、正则表达式或正则表达式数组,可用于仅运行名称与提供的模式匹配的测试。 测试名称模式被解释为 JavaScript 正则表达式。 对于执行的每个测试,也会运行任何相应的测试钩子,例如beforeEach()
。 默认值:undefined
。
- 返回: <TestsStream>
import { tap } from 'node:test/reporters';
import process from 'node:process';
run({ files: [path.resolve('./tests/test.js')] })
.compose(tap)
.pipe(process.stdout);
const { tap } = require('node:test/reporters');
run({ files: [path.resolve('./tests/test.js')] })
.compose(tap)
.pipe(process.stdout);
test([name][, options][, fn])
#
name
<string> 测试的名称,报告测试结果时显示。 默认值:fn
的name
属性,如果fn
没有名称,则为'<anonymous>'
。options
<Object> 测试的配置选项。 支持以下属性:concurrency
<number> | <boolean> 如果提供了一个数字,那么许多测试将在应用程序线程中并行运行。 如果为true
,则所有计划的异步测试在线程内同时运行。 如果是false
,一次只运行一个测试。 如果未指定,则子测试从其父测试继承此值。 默认值:false
。only
<boolean> 如果为真,并且测试上下文配置为运行only
测试,则将运行此测试。 否则跳过测试。 默认值:false
。signal
<AbortSignal> 允许中止正在进行的测试。skip
<boolean> | <string> 如果为真,则跳过测试。 如果提供了字符串,则该字符串将作为跳过测试的原因显示在测试结果中。 默认值:false
。todo
<boolean> | <string> 如果为真,则测试标记为TODO
。 如果提供了字符串,则该字符串会显示在测试结果中作为测试为TODO
的原因。 默认值:false
。timeout
<number> 测试失败的毫秒数。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
fn
<Function> | <AsyncFunction> 被测试的函数。 此函数的第一个参数是TestContext
对象。 如果测试使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。- 返回: <Promise> 测试完成后使用
undefined
解决,或者如果测试在describe()
内运行则立即解决。
test()
函数是从 test
模块导入的值。 每次调用此函数都会向 <TestsStream> 报告测试。
传给 fn
参数的 TestContext
对象可用于执行与当前测试相关的操作。 示例包括跳过测试、添加额外的诊断信息或创建子测试。
test()
返回 Promise
,一旦测试完成就解决。
如果在 describe()
块中调用 test()
,它会立即解析。
返回值通常可以被顶层测试丢弃。
但是,应该使用子测试的返回值来防止父测试先完成并取消子测试,如下例所示。
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
如果完成时间超过 timeout
毫秒,则可以使用 timeout
选项使测试失败。 但是,它不是取消测试的可靠机制,因为正在运行的测试可能会阻塞应用程序线程,从而阻止预定的取消。
test.skip([name][, options][, fn])
#
跳过测试的简写,与 test([name], { skip: true }[, fn])
相同。
test.todo([name][, options][, fn])
#
将测试标记为 TODO
的简写,与 test([name], { todo: true }[, fn])
相同。
test.only([name][, options][, fn])
#
将测试标记为 only
的简写,与 test([name], { only: true }[, fn])
相同。
describe([name][, options][, fn])
#
name
<string> 套件名称,报告测试结果时显示。 默认值:fn
的name
属性,如果fn
没有名称,则为'<anonymous>'
。options
<Object> 套件的配置选项。 支持与test([name][, options][, fn])
相同的选项。fn
<Function> | <AsyncFunction> 套件下的函数声明所有子测试和子套件。 此函数的第一个参数是SuiteContext
对象。 Default: 无操作的函数。- 返回:
undefined
.
从 node:test
模块导入的 describe()
函数。 每次调用此函数都会创建一个子测试。
调用顶层 describe
函数后,所有顶层测试和套件都将执行。
describe.skip([name][, options][, fn])
#
跳过套件的简写,与 describe([name], { skip: true }[, fn])
相同。
describe.todo([name][, options][, fn])
#
将套件标记为 TODO
的简写,与 describe([name], { todo: true }[, fn])
相同。
describe.only([name][, options][, fn])
#
将套件标记为 only
的简写,与 describe([name], { only: true }[, fn])
相同。
it([name][, options][, fn])
#
test()
的简写。
it()
函数是从 node:test
模块导入的。
it.skip([name][, options][, fn])
#
跳过测试的简写,与 it([name], { skip: true }[, fn])
相同。
it.todo([name][, options][, fn])
#
将测试标记为 TODO
的简写,与 it([name], { todo: true }[, fn])
相同。
it.only([name][, options][, fn])
#
将测试标记为 only
的简写,与 it([name], { only: true }[, fn])
相同。
before([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于在运行套件之前创建一个钩子运行。
describe('tests', async () => {
before(() => console.log('about to run some test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
after([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
该函数用于创建一个运行套件后运行的钩子。
describe('tests', async () => {
after(() => console.log('finished running tests'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
beforeEach([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于创建一个在当前套件的每个子测试之前运行的钩子。
describe('tests', async () => {
beforeEach(() => console.log('about to run a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
afterEach([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于创建一个在当前测试的每个子测试之后运行的钩子。
describe('tests', async () => {
afterEach(() => console.log('finished running a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
类:MockFunctionContext
#
MockFunctionContext
类用于检查或操纵通过 MockTracker
API 创建的模拟的行为。
ctx.calls
#
返回用于跟踪模拟调用的内部数组副本的获取器。 数组中的每个条目都是一个具有以下属性的对象。
arguments
<Array> 传递给模拟函数的参数数组。error
<any> 如果模拟函数抛出,则此属性包含抛出的值。 默认值:undefined
。result
<any> 模拟函数返回的值。stack
<Error> 一个Error
对象,其堆栈可用于确定模拟函数调用的调用点。target
<Function> | <undefined> 如果模拟函数是构造函数,则此字段包含正在构造的类。 否则这将是undefined
。this
<any> 模拟函数的this
值。
ctx.callCount()
#
- 返回: <integer> 这个模拟被调用的次数。
此函数返回此模拟已被调用的次数。 此函数比检查 ctx.calls.length
更有效,因为 ctx.calls
是创建内部调用跟踪数组副本的获取器。
ctx.mockImplementation(implementation)
#
implementation
<Function> | <AsyncFunction> 要用作模拟的新实现的函数。
此函数用于更改现有模拟的行为。
以下示例使用 t.mock.fn()
创建模拟函数,调用模拟函数,然后将模拟实现更改为不同的函数。
test('changes a mock behavior', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne);
assert.strictEqual(fn(), 1);
fn.mock.mockImplementation(addTwo);
assert.strictEqual(fn(), 3);
assert.strictEqual(fn(), 5);
});
ctx.mockImplementationOnce(implementation[, onCall])
#
implementation
<Function> | <AsyncFunction> 要用作onCall
指定的调用编号的模拟实现的函数。onCall
<integer> 将使用implementation
的调用编号。 如果指定的调用已经发生,则抛出异常。 默认值: 下次调用的次数。
此函数用于更改单个调用的现有模拟的行为。 一旦调用 onCall
发生,模拟将恢复到没有调用 mockImplementationOnce()
时它会使用的任何行为。
以下示例使用 t.mock.fn()
创建模拟函数,调用模拟函数,将模拟实现更改为下一次调用的不同函数,然后恢复其先前的行为。
test('changes a mock behavior once', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne);
assert.strictEqual(fn(), 1);
fn.mock.mockImplementationOnce(addTwo);
assert.strictEqual(fn(), 3);
assert.strictEqual(fn(), 4);
});
ctx.resetCalls()
#
重置模拟函数的调用历史。
ctx.restore()
#
将模拟函数的实现重置为其原始行为。 调用此函数后仍然可以使用模拟。
类:MockTracker
#
MockTracker
类用于管理模拟功能。 测试运行器模块提供了一个顶层 mock
导出,它是一个 MockTracker
实例。
每个测试还通过测试上下文的 mock
属性提供自己的 MockTracker
实例。
mock.fn([original[, implementation]][, options])
#
original
<Function> | <AsyncFunction> 创建模拟的可选函数。 Default: 无操作的函数。implementation
<Function> | <AsyncFunction> 用作original
的模拟实现的可选函数。 这对于创建针对指定次数的调用表现出一种行为然后恢复original
的行为的模拟非常有用。 默认值:original
指定的函数。options
<Object> 模拟功能的可选配置选项。 支持以下属性:times
<integer> 模拟将使用implementation
的行为的次数。 一旦模拟函数被调用了times
次,它会自动恢复original
的行为。 此值必须是大于零的整数。 默认值:Infinity
。
- 返回: <Proxy> 模拟函数。 模拟函数包含一个特殊的
mock
属性,它是MockFunctionContext
的一个实例,可用于检查和更改模拟函数的行为。
此函数用于创建模拟函数。
以下示例创建了一个模拟函数,每次调用时计数器都会递增 1。 times
选项用于修改模拟行为,以便前两次调用将两个而不是一个添加到计数器。
test('mocks a counting function', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne, addTwo, { times: 2 });
assert.strictEqual(fn(), 2);
assert.strictEqual(fn(), 4);
assert.strictEqual(fn(), 5);
assert.strictEqual(fn(), 6);
});
mock.getter(object, methodName[, implementation][, options])
#
此函数是 MockTracker.method
的语法糖,options.getter
设置为 true
。
mock.method(object, methodName[, implementation][, options])
#
object
<Object> 其方法被模拟的对象。methodName
<string> | <symbol> 要模拟的object
上的方法的标识符。 如果object[methodName]
不是函数,则会抛出错误。implementation
<Function> | <AsyncFunction> 用作object[methodName]
的模拟实现的可选函数。 默认值:object[methodName]
指定的原始方法。options
<Object> 模拟方法的可选配置选项。 支持以下属性:- 返回: <Proxy> 被模拟的方法。 模拟方法包含一个特殊的
mock
属性,它是MockFunctionContext
的实例,可用于检查和更改模拟方法的行为。
此函数用于在现有对象方法上创建模拟。 以下示例演示了如何在现有对象方法上创建模拟。
test('spies on an object method', (t) => {
const number = {
value: 5,
subtract(a) {
return this.value - a;
},
};
t.mock.method(number, 'subtract');
assert.strictEqual(number.subtract.mock.calls.length, 0);
assert.strictEqual(number.subtract(3), 2);
assert.strictEqual(number.subtract.mock.calls.length, 1);
const call = number.subtract.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3]);
assert.strictEqual(call.result, 2);
assert.strictEqual(call.error, undefined);
assert.strictEqual(call.target, undefined);
assert.strictEqual(call.this, number);
});
mock.reset()
#
此函数恢复了此 MockTracker
之前创建的所有模拟的默认行为,并解除了模拟与 MockTracker
实例的关联。 一旦解除关联,模拟仍然可以使用,但 MockTracker
实例不能再用于重置它们的行为或以其他方式与它们交互。
每次测试完成后,都会在测试上下文的 MockTracker
上调用此函数。 如果广泛使用全局 MockTracker
,建议手动调用该函数。
mock.restoreAll()
#
此函数恢复此 MockTracker
之前创建的所有模拟的默认行为。 与 mock.reset()
不同,mock.restoreAll()
不会取消模拟与 MockTracker
实例的关联。
mock.setter(object, methodName[, implementation][, options])
#
此函数是 MockTracker.method
的语法糖,options.setter
设置为 true
。
类:TestsStream
#
成功调用 run()
方法将返回一个新的 <TestsStream> 对象,流式传输代表测试执行的一系列事件。
TestsStream
将按照测试定义的顺序触发事件
事件:'test:coverage'
#
data
<Object>summary
<Object> 包含覆盖率报告的对象。files
<Array> 单个文件的一系列覆盖率报告。 每个报告都是具有以下架构的对象:path
<string> 文件的绝对路径。totalLineCount
<number> 总行数。totalBranchCount
<number> 分支总数。totalFunctionCount
<number> 函数总数。coveredLineCount
<number> 被覆盖的行数。coveredBranchCount
<number> 覆盖的分支数。coveredFunctionCount
<number> 覆盖函数的个数。coveredLinePercent
<number> 覆盖行的百分比。coveredBranchPercent
<number> 覆盖的分支百分比。coveredFunctionPercent
<number> 覆盖的函数百分比。uncoveredLineNumbers
<Array> 一个整数数组,表示未覆盖的行号。
totals
<Object> 包含所有文件覆盖率摘要的对象。totalLineCount
<number> 总行数。totalBranchCount
<number> 分支总数。totalFunctionCount
<number> 函数总数。coveredLineCount
<number> 被覆盖的行数。coveredBranchCount
<number> 覆盖的分支数。coveredFunctionCount
<number> 覆盖函数的个数。coveredLinePercent
<number> 覆盖行的百分比。coveredBranchPercent
<number> 覆盖的分支百分比。coveredFunctionPercent
<number> 覆盖的函数百分比。
workingDirectory
<string> 代码覆盖开始时的工作目录。 这对于显示相对路径名很有用,以防测试更改了 Node.js 进程的工作目录。
nesting
<number> 测试的嵌套级别。
启用代码覆盖率并且所有测试都已完成时触发。
事件:'test:diagnostic'
#
data
<Object>file
<string> | <undefined> 测试文件的路径,如果测试未通过文件运行则未定义。message
<string> 诊断消息。nesting
<number> 测试的嵌套级别。
调用 context.diagnostic
时触发。
事件:'test:fail'
#
data
<Object>details
<Object> 额外的执行元数据。file
<string> | <undefined> 测试文件的路径,如果测试未通过文件运行则未定义。name
<string> 测试名称。nesting
<number> 测试的嵌套级别。testNumber
<number> 测试的序号。todo
<string> | <boolean> | <undefined> 如果调用context.todo
,则存在skip
<string> | <boolean> | <undefined> 如果调用context.skip
,则存在
测试失败时触发。
事件:'test:pass'
#
data
<Object>details
<Object> 额外的执行元数据。duration
<number> 以毫秒为单位的测试持续时间。
file
<string> | <undefined> 测试文件的路径,如果测试未通过文件运行则未定义。name
<string> 测试名称。nesting
<number> 测试的嵌套级别。testNumber
<number> 测试的序号。todo
<string> | <boolean> | <undefined> 如果调用context.todo
,则存在skip
<string> | <boolean> | <undefined> 如果调用context.skip
,则存在
测试通过时触发。
事件:'test:plan'
#
data
<Object>file
<string> | <undefined> 测试文件的路径,如果测试未通过文件运行则未定义。nesting
<number> 测试的嵌套级别。count
<number> 已运行的子测试数。
当给定测试的所有子测试都完成时触发。
事件:'test:start'
#
data
<Object>file
<string> | <undefined> 测试文件的路径,如果测试未通过文件运行则未定义。name
<string> 测试名称。nesting
<number> 测试的嵌套级别。
测试开始时触发。
类:TestContext
#
TestContext
的实例被传给每个测试函数,以便与测试运行器交互。 但是,TestContext
构造函数没有作为 API 的一部分公开。
context.before([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 此函数的第一个参数是TestContext
对象。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于创建在当前测试的子测试之前运行的钩子。
context.beforeEach([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 此函数的第一个参数是TestContext
对象。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于创建一个在当前测试的每个子测试之前运行的钩子。
test('top level test', async (t) => {
t.beforeEach((t) => t.diagnostic(`about to run ${t.name}`));
await t.test(
'This is a subtest',
(t) => {
assert.ok('some relevant assertion here');
},
);
});
context.after([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 此函数的第一个参数是TestContext
对象。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于创建一个在当前测试完成后运行的钩子。
test('top level test', async (t) => {
t.after((t) => t.diagnostic(`finished running ${t.name}`));
assert.ok('some relevant assertion here');
});
context.afterEach([fn][, options])
#
fn
<Function> | <AsyncFunction> 钩子函数。 此函数的第一个参数是TestContext
对象。 如果钩子使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。options
<Object> 钩子的配置选项。 支持以下属性:signal
<AbortSignal> 允许中止正在进行的钩子。timeout
<number> 钩子会在几毫秒后失败。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
此函数用于创建一个在当前测试的每个子测试之后运行的钩子。
test('top level test', async (t) => {
t.afterEach((t) => t.diagnostic(`finished running ${t.name}`));
await t.test(
'This is a subtest',
(t) => {
assert.ok('some relevant assertion here');
},
);
});
context.diagnostic(message)
#
message
<string> 要报告的消息。
此函数用于将诊断写入输出。 任何诊断信息都包含在测试结果的末尾。 此函数不返回值。
test('top level test', (t) => {
t.diagnostic('A diagnostic message');
});
context.name
#
测试名称。
context.runOnly(shouldRunOnlyTests)
#
shouldRunOnlyTests
<boolean> 是否运行only
测试。
如果 shouldRunOnlyTests
为真,则测试上下文将只运行设置了 only
选项的测试。 否则,将运行所有测试。 如果 Node.js 不是使用 --test-only
命令行选项启动的,则此函数是无操作的。
test('top level test', (t) => {
// The test context can be set to run subtests with the 'only' option.
t.runOnly(true);
return Promise.all([
t.test('this subtest is now skipped'),
t.test('this subtest is run', { only: true }),
]);
});
context.signal
#
- <AbortSignal> 可用于在测试中止时中止测试子任务。
test('top level test', async (t) => {
await fetch('some/uri', { signal: t.signal });
});
context.skip([message])
#
message
<string> 可选的跳过消息。
此函数使测试的输出指示测试已跳过。 如果提供了 message
,它会包含在输出中。 调用 skip()
不会终止测试函数的执行。 此函数不返回值。
test('top level test', (t) => {
// Make sure to return here as well if the test contains additional logic.
t.skip('this is skipped');
});
context.todo([message])
#
message
<string> 可选的TODO
消息。
此函数将 TODO
指令添加到测试的输出中。 如果提供了 message
,它会包含在输出中。 调用 todo()
不会终止测试函数的执行。 此函数不返回值。
test('top level test', (t) => {
// This test is marked as `TODO`
t.todo('this is a todo');
});
context.test([name][, options][, fn])
#
name
<string> 子测试的名称,在报告测试结果时显示。 默认值:fn
的name
属性,如果fn
没有名称,则为'<anonymous>'
。options
<Object> 子测试的配置选项。 支持以下属性:concurrency
<number> | <boolean> | <null> 如果提供了一个数字,那么许多测试将在应用程序线程中并行运行。 如果是true
,它将并行运行所有子测试。 如果是false
,它一次只会运行一个测试。 如果未指定,则子测试从其父测试继承此值。 默认值:null
。only
<boolean> 如果为真,并且测试上下文配置为运行only
测试,则将运行此测试。 否则跳过测试。 默认值:false
。signal
<AbortSignal> 允许中止正在进行的测试。skip
<boolean> | <string> 如果为真,则跳过测试。 如果提供了字符串,则该字符串将作为跳过测试的原因显示在测试结果中。 默认值:false
。todo
<boolean> | <string> 如果为真,则测试标记为TODO
。 如果提供了字符串,则该字符串会显示在测试结果中作为测试为TODO
的原因。 默认值:false
。timeout
<number> 测试失败的毫秒数。 如果未指定,则子测试从其父测试继承此值。 默认值:Infinity
。
fn
<Function> | <AsyncFunction> 被测试的函数。 此函数的第一个参数是TestContext
对象。 如果测试使用回调,则回调函数作为第二个参数传入。 Default: 无操作的函数。- 返回: <Promise> 测试完成后使用
undefined
解决。
此函数用于在当前测试下创建子测试。 此函数的行为方式与顶层的 test()
函数相同。
test('top level test', async (t) => {
await t.test(
'This is a subtest',
{ only: false, skip: false, concurrency: 1, todo: false },
(t) => {
assert.ok('some relevant assertion here');
},
);
});
类:SuiteContext
#
SuiteContext
的实例被传给每个套件函数,以便与测试运行器进行交互。 但是,SuiteContext
构造函数没有作为 API 的一部分公开。
context.name
#
套件名称。
context.signal
#
- <AbortSignal> 可用于在测试中止时中止测试子任务。