简体   繁体   中英

How does Mocha execute the 'it' calls? How to execute tests synchronously?

Observe the following tests:

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

The first two tests fail. But I have no idea why! What am I doing wrong?

The test shows the following:

使用Mocha的NPM测试结果

I'm porting QUnit to Mocha and I'm looking where the asserts should go.
In QUnit you have Module -> Test -> Asserts.
Is it here Describe -> Describe -> It's?

You're doing the tests wrong. The entire test, variable setup and all, MUST BE INSIDE the it functions.

What the it functions do is just push your tests to a list that will be executed either by the describe function or by mocha itself. The it functions do NOT execute the tests.

The correct way to write your test is as follows:

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. All tests are executed synchronously unless you pass an argument into the callback of the it function. It's just that they're not executed inside the describe function. The it functions just compiles all your it calls into a list of tests.

Therefore, if you need to do a series of operations you can do this:

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

Note however that this is not recommended because if the first test fails then some of the following tests may fail as well. In this example, if the first test fails because the value of i is not 0 the second test will fail too. However, this pattern may be useful for steps that take a long time to execute (website login for example).


Why do it this way?

This allows mocha to do fancy test reporting like progress bars etc. Without knowing how many tests there are to run (a test is an it function), mocha cannot know what percentage to draw the progress bar.

It also allows mocha to do fancy formatting of error messages. If you've used mocha, you'll notice that mocha collects all error messages (fails) and print them at the end. To do that what mocha does is execute the tests ( it functions) one at a time in a controlled manner and collecting any errors thrown. That's not possible if you rely on javascript syntax alone unless you hack the interpreter in C. But you can do that if you have a list of functions inside an array and execute them one function at a time.

Answering to question, how the execution flow works. Mocha starts with describe block.

In describe block first of all it executes all the code that is not in the it block.

So in your code first of all these 3 statements are executed before executing it blocks

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

Last value assigned to i is 7. Now it will start executing it blocks.

A Solution like on the Mocha Documentation 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);
    });
});

The calling order, as asked in the Question
I tested it with a adapted code from this article http://cwinters.com/2014/09/26/mocha-nested-hook-ordering.html

Here is the code, I used

'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() {});
  });
});

here the result

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)

=> The describe Block will be execute immediately, so multiple variable asignment to the same varible will be overriden by the last one, before any other function is called. The first two test Fail because i==7 when all three tests are executed.

If the sequence is really needed you could use closure , but this would add a lot more complexity .

Looks like the following is the way to go:

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

});

The QUnit.module maps to describe , QUnit.test maps to it and assert maps to expect .

I've written a blog on the subject: Convert QUnit test to Mocha / Chai .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM