Search code examples
javascriptnode.jsunit-testingmocha.jssinon

How to mock constructor call in javascript


How do i mock creating constructor of my parent class in derived class.

here is the example i am testing.

myclass.js

class a {

  constructor() {
     console.log('i am from class a constructor');
   }
  foo() {
    console.log('i am from class a foo method');
  }
}


class b {

  constructor() {
     console.log('i am from class b constructor');
   }
  baz() {
    let obj = new a();
    a.foo();
    console.log('i am from class b baz method');
  }
}

Here is my unittest, using Sinon.js i am mocking. i am creating unittest for class b -> baz() method. my expectation is to calling baz() method should not call actual class a and it should not print console which is in class a constructor.how can i achive this. sinon.createStubInstance() i used to create object but how to mock constructor?

myclass.test.js

describe('myclass' ()=> {
   it('should not call class a constructor', (done) => {
    let b_obj = new b()
    b_obj.baz();
    done()
   });
})

Output printing for above code

i am from class a constructor
i am from class a foo method
i am from class b baz method

Expected Output for above code

// should be mocked .. i am from class a constructor
//should be mocked .. i am from class a foo method
i am from class b baz method

Solution

  • I made a few refactors and using proxyquire to mock class a.

    E.g.

    a.js:

    class a {
      constructor() {
        console.log('i am from class a constructor');
      }
      foo() {
        console.log('i am from class a foo method');
      }
    }
    
    module.exports = a;
    

    b.js:

    const a = require('./a');
    
    class b {
      constructor() {
        console.log('i am from class b constructor');
      }
      baz() {
        let obj = new a();
        obj.foo();
        console.log('i am from class b baz method');
      }
    }
    
    module.exports = b;
    

    b.test.js:

    const b = require('./b');
    const sinon = require('sinon');
    const proxyquire = require('proxyquire');
    
    describe('61108610', () => {
      it('should pass', () => {
        const aInstanceStub = { foo: sinon.stub() };
        const aStub = sinon.stub().returns(aInstanceStub);
        const b = proxyquire('./b', {
          './a': aStub,
        });
        const logSpy = sinon.spy(console, 'log');
        const b_obj = new b();
        b_obj.baz();
        sinon.assert.calledOnce(aStub);
        sinon.assert.calledOnce(aInstanceStub.foo);
        sinon.assert.calledWithExactly(logSpy, 'i am from class b baz method');
      });
    });
    

    unit test results with coverage report:

      61108610
    i am from class b constructor
    i am from class b baz method
        ✓ should pass
    
    
      1 passing (30ms)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |   77.78 |      100 |      50 |   77.78 |                   
     a.js     |   33.33 |      100 |       0 |   33.33 | 3,6               
     b.js     |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------
    

    source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/61108610