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 方法将测试添加到模块中。模块帮助组织、选择和过滤要运行的测试。请参阅§ Organizing your tests

模块可以嵌套在其他模块中。在输出中,测试通常以所有父模块的名称作为前缀。例如: “Grantparent > Parent > Child > my test”。见§ Nested module scope

QUnit.module.only()QUnit.module.skip()QUnit.module.todo() 方法是 QUnit.module() 的别名,它们将 QUnit.test.only() QUnit.test.skip() QUnit.test.todo() 的行为一次应用于所有模块的测试。

钩子

您可以使用钩子来准备夹具,或运行其他设置和拆卸逻辑。 Hooks 可以围绕单个测试运行,也可以围绕整个模块运行。

  • before:在第一次测试之前运行回调。
  • beforeEach :在每次测试之前运行回调。
  • afterEach :每次测试后运行回调。
  • after :在最后一次测试后运行回调。

您可以通过 scoped modulehooks 参数或在模块 options 对象中添加钩子,或通过 QUnit.hooks 为所有测试全局添加钩子。

添加到模块的钩子也将应用于任何嵌套模块中的测试。

运行before 测试的钩子按照添加的顺序从最外层到最内层排序。这意味着测试将首先运行任何全局 beforeEach 钩子,然后是父模块的钩子,最后是添加到测试所在的直接模块的钩子。运行after 测试的钩子按相反的顺序从最内层到最外层排序。换句话说,beforebeforeEach 回调形成 queue ,而 afterEachafter 形成 stack

钩子回调

钩子回调可能是一个异步函数,并且可能返回一个 Promise 或任何其他 then-able。 QUnit 会在继续执行测试之前自动等待你的钩子的异步工作完成。

每个钩子都可以访问相同的 assert 对象,并通过 this 测试上下文,作为钩子运行的 QUnit.test。示例:§ Using the test context

参数 说明
assert(对象) Assert 对象。

不鼓励从钩子中动态创建新的QUnit.test。为了满足 after 钩子只运行一次并成为模块中的最后一个钩子的要求,QUnit 可以将动态定义的测试与父模块相关联,或者作为全局测试。建议通过 QUnit.begin() 定义任何动态测试。

选项对象

您可以使用选项对象添加 hooks

名字 说明
before(函数) 在第一次测试之前运行。
beforeEach(函数) 在每次测试之前运行。
afterEach(函数) 每次测试后运行。
after(函数) 在最后一次测试之后运行。

模块选项对象的属性在每个测试开始时被复制到测试上下文对象。此类属性也可以从钩子回调中更改。见§ Using the test context

示例:§ Declaring module options

嵌套范围

可以嵌套模块以在父模块中的公共标签下对测试进行分组。

模块范围被赋予一个 hooks 对象,该对象可用于在程序上添加 hooks

参数 说明
hooks(对象) 用于添加钩子的对象。

示例:§ Nested module scope

变更日志

QUnit 2.4 引入了 QUnit.module.only()QUnit.module.skip()QUnit.module.todo() 别名。
QUnit 2.0 引入了beforeafter 选项。
QUnit 1.20 引入了nested 范围函数。
QUnit 1.16 beforeEachafterEach引入了选项。
setupteardown选项在 QUnit 1.16 中被弃用并在 QUnit 2.0 中被删除。

例子

组织你的测试

如果在没有nested 回调参数的情况下定义QUnit.module,则所有随后定义的测试将被分组到模块中,直到定义另一个模块。

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 });
  });

  // ...
});