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 钩子,然后运行父模块的钩子,最后运行添加到测试所属的直接模块的钩子。在测试之后运行的钩子,按照相反的顺序从最内层到最外层排序。换句话说,beforebeforeEach 回调函数形成一个 队列,而 afterEachafter 形成一个

钩子回调函数

钩子回调函数可以是异步函数,并且可以返回 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 引入了 beforeafter 选项。
QUnit 1.20 引入了 nested 范围功能。
QUnit 1.16 引入了 beforeEachafterEach 选项。
在 QUnit 1.16 中弃用 setupteardown 选项,并在 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

在钩子中处理异步 thenable 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 });
  });

  // ...
});