QUnit.module()
添加版本:1.0.0.
描述
QUnit.module( name )
QUnit.module( name, nested )
QUnit.module( name, options )
QUnit.module( name, options, nested )
将相关测试分组到一个通用标签下。
参数 | 描述 |
---|---|
name (字符串) |
此测试组的标签。 |
options (对象) |
设置钩子回调。 |
nested (函数) |
用于创建嵌套模块和/或以功能方式添加钩子的范围。 |
模块内的所有测试都将分组到该模块下。可以使用 QUnit.test 方法将测试添加到模块中。模块有助于组织、选择和过滤要运行的测试。请参阅 § 组织您的测试。
模块可以嵌套在其他模块内。在输出中,测试通常以所有父模块的名称为前缀。例如,“Grandparent > Parent > Child > my test”。请参阅 § 嵌套模块范围。
QUnit.module.only()
、QUnit.module.skip()
和 QUnit.module.todo()
方法是 QUnit.module()
的别名,它们将 QUnit.test.only()
、QUnit.test.skip()
或 QUnit.test.todo()
的行为一次性应用于模块的所有测试。
钩子
您可以使用钩子来准备夹具,或运行其他设置和拆卸逻辑。钩子可以在单个测试周围运行,也可以在整个模块周围运行。
before
:在第一个测试之前运行回调。beforeEach
:在每个测试之前运行回调。afterEach
:在每个测试之后运行回调。after
: 在最后一个测试之后运行回调函数。
您可以通过 hooks
参数在 作用域模块 中添加钩子,或在模块 options
对象中添加,或通过 QUnit.hooks 为所有测试添加全局钩子。
添加到模块的钩子也适用于任何嵌套模块中的测试。
在测试之前运行的钩子,按照添加顺序从最外层到最内层排序。这意味着测试将首先运行任何全局 beforeEach 钩子,然后运行父模块的钩子,最后运行添加到测试所属的直接模块的钩子。在测试之后运行的钩子,按照相反的顺序从最内层到最外层排序。换句话说,before
和 beforeEach
回调函数形成一个 队列,而 afterEach
和 after
形成一个 栈。
钩子回调函数
钩子回调函数可以是异步函数,并且可以返回 Promise 或任何其他可 then 的对象。QUnit 将自动等待您的钩子的异步工作完成,然后再继续执行测试。
每个钩子都可以访问与 QUnit.test 相同的 assert
对象,以及通过 this
的测试上下文,该钩子正在为其运行。示例:§ 使用测试上下文。
参数 | 描述 |
---|---|
assert (对象) |
一个 断言 对象。 |
不建议在钩子内部动态创建一个新的 QUnit.test。为了满足 after
钩子只运行一次并且是模块中最后一个钩子的要求,QUnit 可能会将动态定义的测试与父模块相关联,或者作为全局测试。建议通过 QUnit.begin()
定义任何动态测试。
选项对象
您可以使用选项对象添加 钩子。
名称 | 描述 |
---|---|
before (函数) |
在第一个测试之前运行。 |
beforeEach (函数) |
在每个测试之前运行。 |
afterEach (函数) |
在每个测试之后运行。 |
after (函数) |
在最后一个测试之后运行。 |
模块选项对象上的属性在每个测试开始时被复制到测试上下文对象。这些属性也可以从钩子回调中更改。参见 § 使用测试上下文.
示例:§ 声明模块选项.
嵌套范围
模块可以嵌套,以便将测试分组在父模块中的一个通用标签下。
模块范围被赋予一个 hooks
对象,该对象可用于以过程方式添加 钩子.
参数 | 描述 |
---|---|
hooks (对象) |
用于添加钩子的对象。 |
示例:§ 嵌套模块范围.
变更日志
QUnit 2.4 | 引入了 QUnit.module.only() 、QUnit.module.skip() 和 QUnit.module.todo() 别名。 |
QUnit 2.0 | 引入了 before 和 after 选项。 |
QUnit 1.20 | 引入了 nested 范围功能。 |
QUnit 1.16 | 引入了 beforeEach 和 afterEach 选项。在 QUnit 1.16 中弃用 setup 和 teardown 选项,并在 QUnit 2.0 中删除。 |
示例
组织您的测试
如果 QUnit.module
在没有 nested
回调参数的情况下被调用,则所有随后定义的测试将被分组到该模块中,直到定义另一个模块。
QUnit.module('Group A');
QUnit.test('basic test example 1', function (assert) {
assert.true(true, 'this is fine');
});
QUnit.test('basic test example 2', function (assert) {
assert.true(true, 'this is also fine');
});
QUnit.module('Group B');
QUnit.test('basic test example 3', function (assert) {
assert.true(true, 'this is fine');
});
QUnit.test('basic test example 4', function (assert) {
assert.true(true, 'this is also fine');
});
使用现代语法
const { test } = QUnit;
QUnit.module('Group A');
test('basic test example', assert => {
assert.true(true, 'this is fine');
});
test('basic test example 2', assert => {
assert.true(true, 'this is also fine');
});
QUnit.module('Group B');
test('basic test example 3', assert => {
assert.true(true, 'this is fine');
});
test('basic test example 4', assert => {
assert.true(true, 'this is also fine');
});
声明模块选项
QUnit.module('module A', {
before: function () {
// prepare something once for all tests
},
beforeEach: function () {
// prepare something before each test
},
afterEach: function () {
// clean up after each test
},
after: function () {
// clean up once after all tests are done
}
});
嵌套模块范围
const { test } = QUnit;
QUnit.module('Group A', hooks => {
test('basic test example', assert => {
assert.true(true, 'this is fine');
});
test('basic test example 2', assert => {
assert.true(true, 'this is also fine');
});
});
QUnit.module('Group B', hooks => {
test('basic test example 3', assert => {
assert.true(true, 'this is fine');
});
test('basic test example 4', assert => {
assert.true(true, 'this is also fine');
});
});
嵌套模块上的钩子
使用 before
/beforeEach
钩子将排队到嵌套模块。 after
/afterEach
钩子将堆叠在嵌套模块上。
const { test } = QUnit;
QUnit.module('My Group', hooks => {
// It is valid to call the same hook methods more than once.
hooks.beforeEach(assert => {
assert.ok(true, 'beforeEach called');
});
hooks.afterEach(assert => {
assert.ok(true, 'afterEach called');
});
test('with hooks', assert => {
// 1 x beforeEach
// 1 x afterEach
assert.expect(2);
});
QUnit.module('Nested Group', hooks => {
// This will run after the parent module's beforeEach hook
hooks.beforeEach(assert => {
assert.ok(true, 'nested beforeEach called');
});
// This will run before the parent module's afterEach
hooks.afterEach(assert => {
assert.ok(true, 'nested afterEach called');
});
test('with nested hooks', assert => {
// 2 x beforeEach (parent, current)
// 2 x afterEach (current, parent)
assert.expect(4);
});
});
});
使用测试上下文
测试上下文对象暴露给钩子回调。
QUnit.module('Machine Maker', {
beforeEach: function () {
this.maker = new Maker();
this.parts = ['wheels', 'motor', 'chassis'];
}
});
QUnit.test('makes a robot', function (assert) {
this.parts.push('arduino');
assert.equal(this.maker.build(this.parts), 'robot');
assert.deepEqual(this.maker.log, ['robot']);
});
QUnit.test('makes a car', function (assert) {
assert.equal(this.maker.build(this.parts), 'car');
this.maker.duplicate();
assert.deepEqual(this.maker.log, ['car', 'car']);
});
使用嵌套作用域时,测试上下文也可用。注意,箭头函数中无法使用 this
绑定。
const { test } = QUnit;
QUnit.module('Machine Maker', hooks => {
hooks.beforeEach(function () {
this.maker = new Maker();
this.parts = ['wheels', 'motor', 'chassis'];
});
test('makes a robot', function (assert) {
this.parts.push('arduino');
assert.equal(this.maker.build(this.parts), 'robot');
assert.deepEqual(this.maker.log, ['robot']);
});
test('makes a car', function (assert) {
assert.equal(this.maker.build(this.parts), 'car');
this.maker.duplicate();
assert.deepEqual(this.maker.log, ['car', 'car']);
});
});
使用 JavaScript 自身的词法作用域可能更方便。
const { test } = QUnit;
QUnit.module('Machine Maker', hooks => {
let maker;
let parts;
hooks.beforeEach(() => {
maker = new Maker();
parts = ['wheels', 'motor', 'chassis'];
});
test('makes a robot', assert => {
parts.push('arduino');
assert.equal(maker.build(parts), 'robot');
assert.deepEqual(maker.log, ['robot']);
});
test('makes a car', assert => {
assert.equal(maker.build(parts), 'car');
maker.duplicate();
assert.deepEqual(maker.log, ['car', 'car']);
});
});
模块钩子与 Promise
在钩子中处理异步 then
able Promise 结果的示例。此示例使用 ES6 Promise 接口,该接口在连接或断开数据库连接后完成。
QUnit.module('Database connection', {
before: function () {
return new Promise(function (resolve, reject) {
DB.connect(function (err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
},
after: function () {
return new Promise(function (resolve, reject) {
DB.disconnect(function (err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
});
仅运行测试子集
使用 QUnit.module.only()
将整个模块的测试视为使用 QUnit.test.only
而不是 QUnit.test
。
QUnit.module('Robot', hooks => {
// ...
});
// Only execute this module when developing the feature,
// skipping tests from other modules.
QUnit.module.only('Android', hooks => {
let android;
hooks.beforeEach(() => {
android = new Android();
});
QUnit.test('Say hello', assert => {
assert.strictEqual(android.hello(), 'Hello, my name is AN-2178!');
});
QUnit.test('Basic conversation', assert => {
android.loadConversationData({
Hi: 'Hello',
"What's your name?": 'My name is AN-2178.',
'Nice to meet you!': 'Nice to meet you too!',
'...': '...'
});
assert.strictEqual(
android.answer("What's your name?"),
'My name is AN-2178.'
);
});
// ...
});
使用 QUnit.module.skip()
将整个模块的测试视为使用 QUnit.test.skip
而不是 QUnit.test
。
QUnit.module('Robot', hooks => {
// ...
});
// Skip this module's tests.
// For example if the android tests are failing due to unsolved problems.
QUnit.module.skip('Android', hooks => {
let android;
hooks.beforeEach(() => {
android = new Android();
});
QUnit.test('Say hello', assert => {
assert.strictEqual(android.hello(), 'Hello, my name is AN-2178!');
});
QUnit.test('Basic conversation', assert => {
// ...
assert.strictEqual(
android.answer('Nice to meet you!'),
'Nice to meet you too!'
);
});
// ...
});
使用 QUnit.module.todo()
表示正在开发的功能,并且已知尚未通过所有测试。这将整个模块的测试视为使用 QUnit.test.todo
而不是 QUnit.test
。
QUnit.module.todo('Robot', hooks => {
let robot;
hooks.beforeEach(() => {
robot = new Robot();
});
QUnit.test('Say', assert => {
// Currently, it returns undefined
assert.strictEqual(robot.say(), "I'm Robot FN-2187");
});
QUnit.test('Move arm', assert => {
// Move the arm to point (75, 80). Currently, each throws a NotImplementedError
robot.moveArmTo(75, 80);
assert.deepEqual(robot.getPosition(), { x: 75, y: 80 });
});
// ...
});