如何优化关键词排名快速首页,seo代运营,wordpress新界面,我想自己建立一个网站参考 https://nodejs.org/dist/latest-v20.x/docs/api/test.html#test-runner 在之前#xff0c;我们写单元测试#xff0c;必须安装第三方依赖包#xff0c;而从node 20.0.0 版本之后#xff0c;可以告别繁琐的第三方依赖包啦#xff0c;可直接使用node的内置test runner… 参考 https://nodejs.org/dist/latest-v20.x/docs/api/test.html#test-runner 在之前我们写单元测试必须安装第三方依赖包而从node 20.0.0 版本之后可以告别繁琐的第三方依赖包啦可直接使用node的内置test runner。相关功能在20.0.0版本后才稳定要使用test runner请安装node版本20.0.0。
使用
import test from node:test;注意必须使用node:test下面的代码将不会生效
import test from test;通过test模块创建的测试由单个函数组成该函数以以下三种方式之一进行处理:
同步函数如果抛出异常则认为失败否则认为通过。返回Promise的函数如果Promise rejects则认为失败如果resolves则认为通过。接收回调函数的函数如果回调函数的第一个参数是true则认为失败如果是false则认为通过。如果测试函数接收的回调函数也返回Promise则测试将失败。
示例
同步函数未抛出异常测试通过
test(synchronous passing test, (t) {assert.strictEqual(1, 1);
});同步函数抛出异常测试失败
test(synchronous failing test, (t) {assert.strictEqual(1, 2);
});返回Promise的函数Promise resolves测试通过
test(asynchronous passing test, async (t) {assert.strictEqual(1, 1);
});返回Promise的函数Promise rejected测试失败
test(asynchronous failing test, async (t) {assert.strictEqual(1, 2);
});直接使用Promise rejected测试失败
test(failing test using Promises, (t) {return new Promise((resolve, reject) {setImmediate(() {reject(new Error(this will cause the test to fail));});});
});使用setImmediate()调用done()不传参
test(callback passing test, (t, done) {setImmediate(done);
});使用setImmediate()调用done()传参Error对象测试失败。
test(callback failing test, (t, done) {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()方法跳过单个测试如下面的示例所示。
跳过该测试选项但不提供任何提示。
test(skip option, { skip: true }, (t) {// 这里的代码不会执行
});跳过该测试选项提供提示。
test(skip option with message, { skip: this is skipped }, (t) {// 这里的代码不会执行
});如果测试包含额外的逻辑请确保返回到正确的位置。
test(skip() method, (t) {// 返回额外的逻辑t.skip();
});test(skip() method with message, (t) {// 返回额外的逻辑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;only 测试
如果Node.js以--test-only命令行启动则可以通过将only属性传递给应该运行的测试来跳过除选定子集之外的所有顶级测试。当运行具有only属性集的测试时也会运行所有子测试。测试上下文的runOnly()方法可用于在子测试级别实现相同的行为。
// 假设 Node.js 使用 --test-only 命令行运行
// 设置了“only”属性此测试会运行
test(this test is run, { only: true }, async (t) {// 在此测试中默认运行所有子测试await t.test(running subtest);// 可以使用“only”属性更新测试上下文只运行子测试中有only属性的测试t.runOnly(true);await t.test(this subtest is now skipped);await t.test(this subtest is run, { only: true });// 切换上下文回执行所有子测试t.runOnly(false);await t.test(this subtest is now run);// 明确不运行以下测试await t.test(skipped subtest 3, { only: false });await t.test(skipped subtest 4, { skip: true });
});// 未设置“only”选项此测试会被跳过
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-patterntest[1-3]选项启动Node.js将导致测试运行器执行test 1、test 2和test 3。如果test 1不匹配测试名称那么它的子测试就算名称匹配也不会执行。同一组测试也可以通过多次传递--test-name-pattern来执行(例如--test-name-patterntest 1--test-name-patterntest 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);});// 测试在此行之后结束
});从命令行运行测试
Node.js测试运行器可以通过传递--test标志从命令行调用:
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模块支持在测试期间通过顶级mock对象进行模拟。下面的示例创建一个监视函数该函数将两个数字相加然后使用spy来断言函数是否按预期调用。
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);// 重置全局跟踪的mockmock.reset();
});同样的模拟功能也暴露在每个测试的TestContext对象上。下面的示例使用TestContext上公开的API在对象方法上创建一个spy。通过测试上下文进行模拟的好处是一旦测试结束测试运行器将自动恢复所有模拟的功能。
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);
});Timers
模拟计时器是软件测试中常用的一种技术用于模拟和控制计时器的行为例如setInterval和setTimeout而无需实际等待指定的时间间隔。
有关方法和特性的完整列表请参考MockTimers类。
这允许开发人员为依赖时间的功能编写更可靠和可预测的测试。
下面的例子展示了如何模拟setTimeout。使用.enable([setTimeout]);它将模拟node:timers和node:timers/promises模块中的setTimeout函数以及node .js全局上下文中的setTimeout函数。
注意: 此API目前不支持import {setTimeout} from node:timers等解构函数。
import assert from node:assert;
import { mock, test } from node:test;test(mocks setTimeout to be executed synchronously without having to actually wait for it, () {const fn mock.fn();// 选择要模拟的内容mock.timers.enable([setTimeout]);setTimeout(fn, 9999);assert.strictEqual(fn.mock.callCount(), 0);// 推进时间mock.timers.tick(9999);assert.strictEqual(fn.mock.callCount(), 1);// 重置全局跟踪的mockmock.timers.reset();// 如果调用reset mock instance它也会重置计时器实例mock.reset();
});同样的模拟功能也暴露在每个测试的TestContext对象的mock属性中。通过测试上下文进行模拟的好处是一旦测试结束测试运行器将自动恢复所有模拟计时器功能。
import assert from node:assert;
import { test } from node:test;test(mocks setTimeout to be executed synchronously without having to actually wait for it, (context) {const fn context.mock.fn();// 选择要模拟的内容context.mock.timers.enable([setTimeout]);setTimeout(fn, 9999);assert.strictEqual(fn.mock.callCount(), 0);// 推进时间context.mock.timers.tick(9999);assert.strictEqual(fn.mock.callCount(), 1);
});测试reporter
node:test模块支持传递--test-reporter标志让测试运行器使用特定的reporter。
支持以下内置reporter:
tap : tap reporter 以TAP格式输出测试结果。spec : spec reporter 以人类可读的格式输出测试结果。dot: dot reporter 以紧凑的格式输出测试结果其中通过的测试用.表示失败的测试用X表示。
当sdout是TTY时默认情况下使用spec reporter。否则默认使用tap reporter。
这些 reporter 的确切输出可能会在Node.js的不同版本之间发生变化不应该以编程方式依赖于它们。如果需要对测试运行器的输出进行编程访问请使用发出的事件。
reporter 可通过node:test/reports模块获得:
import { tap, spec, dot } from node:test/reporters;自定义reporter
--test-reporter可以用来指定自定义 reporter 的路径。自定义 reporter 是一个导出stream.compose接受的值的模块。reporter 应该转换由发出的事件。
使用stream.Transform的自定义 reporter 的示例:
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;提供给--test-reporter的值应该是一个字符串类似于JavaScript代码中import()中使用的字符串或者是提供给--import的值。
多种reporter
可以多次指定--test-reporter标志以多种格式报告测试结果。在这种情况下需要使用--test-reporter-destination为每个报告程序指定一个目标。目标可以是stdout、stderr或文件路径。reporter和目标按照指定的顺序配对。
在下面的例子中spec reporter 将输出到 stdout, dot reporter 将输出到file.txt:
node --test-reporterspec --test-reporterdot --test-reporter-destinationstdout --test-reporter-destinationfile.txt当指定了单个reporter时除非显式地提供了目标否则将默认为stdout。