Mocha的before()函数的目的是什么?

时间:2014-10-10 19:38:56

标签: javascript unit-testing mocha

Mocha有几个“钩子”可以在与测试用例本身分开的测试中运行辅助功能(清理数据库,创建模拟文件等)。

但是,对于before() beforeEach(),我得到的那个),它似乎非常多余。

before()在当前套件中的所有测试之前运行逻辑一次,那么为什么我甚至需要将它包装在一个函数中呢?

以下两者之间没有可观察到的差异:

describe('Something', function() {
    before(doSomePreTestLogic);
    //Tests ahoy
});

describe('Something', function() {
    doSomePreTestLogic();
    //Tests ahoy
});

before()包装我的预测试逻辑有什么意义?

3 个答案:

答案 0 :(得分:12)

您可能会在测试中选择before()挂钩,这有几个不同的原因:

<强>语义

这可能是最大的一个。有时您可能需要在运行实际测试之前执行任务,例如在数据库中填充一些虚拟数据。您当然可以在测试本身中执行此操作,但如果您在预填充时遇到错误,并且在运行实际测试用例之前,则会抛弃您的报告。通过使用before()钩子,您可以在逻辑上,语义上有效地插入这种逻辑。

清除异步测试

就像mocha测试可以是异步的一样,你的before()钩子逻辑也是如此。回到预填充示例,这很方便,因为这意味着您的所有异步预测试逻辑都不会在所有实际测试逻辑上强制执行另一级别的缩进。

与其他挂钩的一致性:

Mocha还提供了其他几个钩子,即:after()beforeEach()afterEach()。你可能也会问同样的问题关于所有这些其他钩子,但是如果你认为它们中的任何一个都有一个有效的存在,那么真的需要包括before()来完善API。

答案 1 :(得分:5)

The Upshot

直接放在构建测试套件的describe回调代码中。我正在讨论对it的调用,以及可能循环遍历表或文件以声明一堆测试的函数(通过在循环中调用it)。

将实际初始化测试所依赖的状态的代码放入内部钩子。

所有其他考虑都是次要的。

让我解释一下......

背景

Mocha分两个阶段执行测试套件:

  1. 它发现了哪些测试存在。在此阶段,它将立即执行传递给describe的回调并记录将来的调用传递给声明测试的函数的回调(it声明钩子(beforebeforeEachafter等)的函数和函数。

  2. 它运行测试。在此阶段,它将运行之前记录的回调。

  3. 差异

    所以请考虑这个例子:

    function dump () { console.log("running:", this.test.fullTitle()); }
    describe("top", function () {
        before(dump);
        it("test 1", dump);
        it("test 2", dump);
        describe("level 1", function () {
            before(dump);
            it("test 1", dump);
            it("test 2", dump);
        });
    });
    

    请注意fullTitle从顶级describe开始,通过任何嵌套的describe向下到it或包含呼叫。与spec记者一起运行并仅保留running:行,您将获得:

    running: top "before all" hook: dump
    running: top test 1
    running: top test 2
    running: top level 1 "before all" hook: dump
    running: top level 1 test 1
    running: top level 1 test 2
    

    请注意钩子的顺序,以及如何在各自的describe回调中声明的测试之前立即执行。

    然后考虑这个套件:

    function dump () { console.log("running:", this.test.fullTitle()); }
    function directDump() { console.log("running (direct):", this.fullTitle()); }
    describe("top", function () {
        directDump.call(this);
        it("test 1", dump);
        it("test 2", dump);
        describe("level 1", function () {
            directDump.call(this);
            it("test 1", dump);
            it("test 2", dump);
        });
    });
    

    使用spec记者运行并仅保留running:行,您将获得:

    running (direct): top
    running (direct): top level 1
    running: top test 1
    running: top test 2
    running: top level 1 test 1
    running: top level 1 test 2
    

    请注意directDump的两次调用如何在其他任何内容之前运行。

    后果

    1. 如果您直接放入describe回调中的任何初始化代码失败,整个运行会立即失败。不会执行任何测试。故事结束。

    2. 如果放在before挂钩中的任何初始化代码失败,后果都会被包含。首先,因为before挂钩只是运行目前需要,有机会任何先前安排的测试可以运行。此外,Mocha只会跳过那些依赖于before钩子的测试。例如,让我们假设这个套件:

      function dump () { console.log("running:", this.test.fullTitle()); }
      describe("top", function () {
          before(dump);
          it("test 1", dump);
          it("test 2", dump);
          describe("level 1", function () {
              before(function () { throw new Error("foo"); });
              it("test 1", dump);
              it("test 2", dump);
          });
      
          describe("level 1 (second)", function () {
              before(dump);
              it("test 1", dump);
              it("test 2", dump);
          });
      });
      

      如果您使用spec报告者运行它,整个输出(减去堆栈跟踪)将类似于:

        top
      running: top "before all" hook: dump
      running: top test 1
          ✓ test 1
      running: top test 2
          ✓ test 2
          level 1
            1) "before all" hook
          level 1 (second)
      running: top level 1 (second) "before all" hook: dump
      running: top level 1 (second) test 1
            ✓ test 1
      running: top level 1 (second) test 2
            ✓ test 2
      
      
        4 passing (5ms)
        1 failing
      
        1) top level 1 "before all" hook:
           Error: foo
           [stack trace]
      

      注意a)在失败的钩子之前运行了一些测试,以及b)Mocha仍然运行不依赖于钩子的测试。

答案 2 :(得分:1)

语义,在机器和人类层面。

此外,它使测试代码与“导出”界面保持一致,例如,

module.exports = {
  before: function(){
    // ...
  },

  'Array': {
    '#indexOf()': {
      'should return -1 when not present': function(){
        [1,2,3].indexOf(4).should.equal(-1);
      }
    }
  }
};