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

  // ...
});