stackjlei
stackjlei

Reputation: 10035

What is the purpose of Mocha's #beforeEach when you can just run code inside the #describe scope?

I'm learning TDD from this article and the author talks about how Mocha's beforeEach will run a code before each assertion for you. But I don't understand why you need to do that when you can just run the code in the describe scope.

describe('Test suite for UserComponent', () => {
  beforeEach(() => {
    // Prevent duplication
    wrapper = shallow(<UserComponent
                            name={ 'Reign' }
                            age={ 26 } />);
  });

  it('UserComponent should exist', () => {
    expect(wrapper).to.exist;
  });

  it('Correctly displays the user name and age in paragraphs wrapped under a parent div', () => {
    expect(wrapper.type()).to.equal('div');
    // more code...
  });
});

But not using the beforeEach would still work -

describe('Test suite for UserComponent', () => {

wrapper = shallow(<UserComponent
                        name={ 'Reign' }
                        age={ 26 } />);

  it('UserComponent should exist', () => {
    expect(wrapper).to.exist;
  });

  it('Correctly displays the user name and age in paragraphs wrapped under a parent div', () => {
    expect(wrapper.type()).to.equal('div');
    // more code...
  });
});

Upvotes: 3

Views: 1293

Answers (1)

Louis
Louis

Reputation: 151411

beforeEach is executed before each test. This iteration is lost when the code is moved from beforeEach to be directly inside the function passed to describe. However, that's not all.

In some cases, code executed directly inside the function passed to describe can perform the same task as a beforeEach hook. For instance, if its function is to initialize a read-only structure that is local to the test in the describe block, then you could skip the beforeEach hook.

However, Mocha executes right away all the callbacks that are passed to describe calls whereas a beforeEach call registers the function passed to it for future execution, and it will be executed only if needed. If the initialization is expensive it is better to use a beforeEach hook because if you make use of --grep to select only some test, or use it.only to run a single test, then Mocha will run the hook only if it pertains to the test it will actually run. If you have the initialization code in describe, Mocha cannot skip it so you'll pay the initialization cost every time. However, if you are going to use a hook and the data is immutable, then before is better than beforeEach because it will run just once instead of before each test.

Then there are cases where running code in directly in the function passed to describe simply won't work. Imagine in the following that sharedResource is a resource that all tests need to use. It could be a third-party library that carries state, for instance. Some tests need it to be set to a certain state. Other tests need it to be in a different state. This does not work:

"use strict";

const assert = require('assert');

let sharedResource;

describe("in condition a", () => {
    sharedResource = true;

    it("sharedResource is true", () => assert(sharedResource));
});

describe("in condition b", () => {
    sharedResource = false;

    it("sharedResource is false", () => assert(!sharedResource));
});

The first test will fail because the execution order of the key statements is:

  1. sharedResource = true;
  2. sharedResource = false;
  3. assert(sharedResource);
  4. assert(!sharedResource);

The problem can be easily fixed by using beforeEach. This runs fine:

"use strict";

const assert = require('assert');

let sharedResource;

describe("in condition a", () => {
    beforeEach(() => {
        sharedResource = true;
    });

    it("sharedResource is true", () => assert(sharedResource));
});

describe("in condition b", () => {
    beforeEach(() => {
        sharedResource = false;
    });

    it("sharedResource is false", () => assert(!sharedResource));
});

Upvotes: 3

Related Questions