Jorayen Jorayen - 6 months ago 11
Node.js Question

Node.js sinon stubbing a function in parallel executions causes failed tests

I have 2 test cases which test the same function just taking 2 different executions paths, so to illustrate:

MyClass.prototype.functionBeingTested = function() {
if (this.check1()) {
this.isCheck1Called = true;
} else if (this.check2()) {
this.isCheck1Called = false;
} else {
...
}
};


My 2 test cases are as follow:

it('should take check1() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check1Stub sinon.stub(MyClass.prototype, 'check1');
check1Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(true);
});

it('should take check2() execution path', function() {
var myClass= new MyClass({}, {}, {});
var check2Stub sinon.stub(MyClass.prototype, 'check2');
check2Stub.returns(true);
myClass.functionBeingTested();
myClass.isCheck1Called.should.equal(false);
});


Now by default,
check1()
returns false so I don't stub it in the second test case, but by the time the second case is running, the
check1()
function stub is still active and causes the second case to enter the execution path of the first case as-well, making the second case test fail.

I understand it's a problem of test running in parallel and the first sinon stub still being used by the first test case, is there anyway I can solve this problem?

Answer

At the end of the first test, you should restore the original method (which is always a good thing, to prevent tests from being influenced by previous tests):

check1Stub.restore()

Or, alternatively, you can use a Sinon sandbox to run each test in:

describe('MyClass', function() {

  beforeEach(function() {
    this.sinon = sinon.sandbox.create();
  });

  afterEach(function() {
    this.sinon.restore();
  });

  it('should take check1() execution path', function() {
      var myClass    = new MyClass({}, {}, {});
      // `this.sinon` is the sandbox
      var check1Stub = this.sinon.stub(MyClass.prototype, 'check1');
      check1Stub.returns(true);
      myClass.functionBeingTested();
      myClass.isCheck1Called.should.equal(true);
  });

  it('should take check2() execution path', function() {
      var myClass    = new MyClass({}, {}, {});
      var check2Stub = this.sinon.stub(MyClass.prototype, 'check2');
      check2Stub.returns(true);
      myClass.functionBeingTested();
      myClass.isCheck1Called.should.equal(false);
  });
});

(See mocha-sinon, which does exactly the same)