Mocha 如何执行“it”调用?如何同步执行测试?

Posted

技术标签:

【中文标题】Mocha 如何执行“it”调用?如何同步执行测试?【英文标题】:How does Mocha execute the 'it' calls? How to execute tests synchronously? 【发布时间】:2016-08-02 18:48:51 【问题描述】:

观察以下测试:

describe("Testing i", function()

    var i = 0;
    it('i should be 0', function() 
        expect(i).to.equal(0);
    );

    i++;
    it('i should be 1', function() 
        expect(i).to.equal(1);
    );

    i= 7;
    it('i should be 7', function() 
        expect(i).to.equal(7);
    );
);

前两个测试失败。但我不知道为什么!我做错了什么?

测试显示如下:

我正在将 QUnit 移植到 Mocha,我正在寻找断言应该去哪里。 在 QUnit 中有 Module -> Test -> Asserts。 是在这里吗 描述 -> 描述 -> 是吗?

【问题讨论】:

错误/失败输出是什么? 我将其添加为图片。 看起来回调没有直接执行... 我同意它不是重复的。 @Louis 的根本原因可能相同,但观察到的行为不同。答案也不适用于这个问题。这里发布的答案更适合这个问题。 【参考方案1】:

你做错了测试。整个测试、变量设置和所有内容都必须在 it 函数中。

it 函数所做的只是将您的测试推送到一个列表,该列表将由 describe 函数或 mocha 本身执行。 it 函数不执行测试。

编写测试的正确方法如下:

describe("Testing i", function()

    it('i should be 0', function() 
        var i = 0;
        expect(i).to.equal(0);
    );

    it('i should be 1', function() 
        var i = 0;
        i++;
        expect(i).to.equal(1);
    );

    it('i should be 7', function() 
        var i = 0;
        i = 7;
        expect(i).to.equal(7);
    );
);

FWIW。除非您将参数传递到 it 函数的回调中,否则所有测试都会同步执行。只是它们没有在describe 函数中执行。 it 函数只是将你所有的 it 调用编译成一个测试列表。

因此,如果需要进行一系列操作,可以这样做:

describe("Testing i", function()
    var i;

    it('i should be 0', function() 
        i = 0;
        expect(i).to.equal(0);
    );

    it('i should be 1', function() 
        i++;
        expect(i).to.equal(1);
    );

    it('i should be 7', function() 
        i = 7;
        expect(i).to.equal(7);
    );
);

但请注意,不建议这样做,因为如果第一个测试失败,那么以下一些测试也可能会失败。在这个例子中,如果第一个测试因为i 的值不为 0 而失败,那么第二个测试也将失败。但是,这种模式对于需要很长时间执行的步骤(例如网站登录)可能很有用。


为什么要这样?

这使得 mocha 可以进行花哨的测试报告,例如进度条等。在不知道要运行多少测试(测试是 it 函数)的情况下,mocha 无法知道绘制进度条的百分比。

它还允许 mocha 对错误消息进行精美的格式化。如果您使用过 mocha,您会注意到 mocha 会收集所有错误消息(失败)并在最后打印出来。为此,mocha 所做的是以受控方式一次执行一个测试(it 函数)并收集所有抛出的错误。如果您只依赖 javascript 语法,除非您破解 C 中的解释器,否则这是不可能的。但是如果您在数组中有一个函数列表并一次执行一个函数,则可以做到这一点。

【讨论】:

我需要一个接一个地做一系列的测试。我可以在一个 it 中做多个期望,但是我怎样才能告诉 mocha 每个期望做什么呢?我正在使用同步事件处理进行一些测试。 每个it 会一个接一个地被同步调用。只需将所有代码移动到 it 块中,它们就会起作用。不建议这样做,因为一个失败的测试将导致所有后续测试失败。【参考方案2】:

回答问题,执行流程是如何工作的。 Mocha 以描述块开头。

在 describe 块中,它首先执行所有不在 it 块中的代码。

因此,在您的代码中,首先执行这 3 条语句,然后再执行 it

var i = 0;
  i++;
  i=7;

最后分配给 i 的值为 7。 现在它将开始执行它的块。

【讨论】:

【参考方案3】:

类似 Mocha 文档中的解决方案 https://mochajs.org/

describe("Testing i", function()

    var i;
    it('i should be 0', function() 
        i = 0;
        expect(i).to.equal(0);
    );


    it('i should be 1', function() 
        i++;
        expect(i).to.equal(1);
    );

    it('i should be 7', function() 
        i= 7;
        expect(i).to.equal(7);
    );
);

问题中提出的调用顺序 我使用本文http://cwinters.com/2014/09/26/mocha-nested-hook-ordering.html

中的改编代码对其进行了测试

这是我使用的代码

'use strict';

describe('level 1', function() 
  before(function()  console.log("L1 - before") );
  beforeEach(function()  console.log("L1 - beforeEach") );
  after(function()  console.log("L1 - after") );
  afterEach(function()  console.log("L1 - afterEach") );

console.log("inner DESCRIBE BEFORE L1A")  // equivalent to asigning the variable the first time
  it('L1 test A', function() );
 console.log("inner DESCRIBE BEFORE L1B") // equivalent to asigning the variable the second time
  it('L1 test B', function() );

  describe('level 2', function() 
    before(function()  console.log("L2 - before") );
    beforeEach(function()  console.log("L2 - beforeEach") );
    after(function()  console.log("L2 - after") );
    afterEach(function()  console.log("L2 - afterEach") );

    it('L2 test A', function() );
    it('L2 test B', function() );
  );
);

这里是结果

inner DESCRIBE BEFORE L1A     // execute First
inner DESCRIBE BEFORE L1B     // execute Second


  level 1                     // now the test are executed
L1 - before
L1 - beforeEach
    √ L1 test A
L1 - afterEach
L1 - beforeEach
    √ L1 test B
L1 - afterEach
    level 2
L2 - before
L1 - beforeEach
L2 - beforeEach
      √ L2 test A
L2 - afterEach
L1 - afterEach
L1 - beforeEach
L2 - beforeEach
      √ L2 test B
L2 - afterEach
L1 - afterEach
L2 - after
L1 - after


4 passing (64ms)

=> describe 块将立即执行,因此在调用任何其他函数之前,同一变量的多个变量分配将被最后一个覆盖。 前两个测试失败,因为 i==7 当所有三个测试都执行时。

如果真的需要这个序列,你可以使用闭包,但这会增加很多复杂性

【讨论】:

你确定解决方案是多重的吗?我感觉解决方案可能是多重期望。但我不确定…… 这取决于断言/期望。一般来说,单元测试应该只测试一个“事物”。如果必须使用各种断言/期望来测试这个“一件事”,那么多个断言/期望是有效的/要走的路。如果有不同的单位,拆分它会是更好的选择。尽管如此,如果可能的话,我会尝试在beforeEach 部分设置(环境)测试,以避免混淆 @KeesC.Bakker:it 是一项需要测试的功能。每个特性或功能可能需要断言多个事物。所以这取决于。如果您的多个it 只是测试一个功能,那么将它们组合成一个it。如果您的单个 it 正在测试两个功能,则将其拆分。关键是将测试读成英文句子it should do what,然后添加语法:it('should do what',function())。如果您可以将it 描述为特性、功能、边缘情况或错误,那么it 应该是一个单独的it【参考方案4】:

看起来下面是要走的路:

describe("Testing i", function()

    it('i increments', function()

        var i = 0;
        expect(i, 'i should be 0').to.equal(0);

        i++;
        expect(i, 'i should be 1').to.equal(1);

        i = 7;
        expect(i, 'i should be 7').to.equal(7);
    );

);

QUnit.module 映射到 describeQUnit.test 映射到 itassert 映射到 expect

我已经写了一篇关于这个主题的博客:Convert QUnit test to Mocha / Chai。

【讨论】:

也许您应该发布您正在尝试测试的确切内容(例如,如果您想将值从一个测试“携带”到下一个测试,您可以将它们附加到 this对象,它可用于每个测试,或者在 describe 块中声明一个变量,就像 @winner_joiner 在他们的回答中提出的那样)。 我添加了一系列测试。我正在将我的 QUnit 测试移植到 Mocha 框架。 我快速编写了一些代码here。 result 的范围是 describe 块,这意味着您可以在测试之间“重用”它。 您仍然可以为每个期望创建单独的测试(根据 my gist,IMO 比在同一个测试中有很多期望更干净。

以上是关于Mocha 如何执行“it”调用?如何同步执行测试?的主要内容,如果未能解决你的问题,请参考以下文章

在 mocha 中,如何在执行另一个测试之前等待异步测试结束?

Mocha describe 生命周期

Mocha.js 101同步异步与 Promise

在mocha测试中调用异步函数如何避免超时错误:超过2000ms的超时

如何正确地在 mocha.opts 中需要一个模块?

如何使用 mocha 在 reactjs 中测试此异步方法调用