Search code examples
typescriptunit-testingsinon

Sinon mock class


I have a class:

export default class A {
  data: string
  constructor(data?: any) {
    if (data !== undefined) {
      this.data = data.stingValue
    }
  }
}

Then I have another class which is using A constructor inside a public method:

export default class B {
  public doSomething(data: any) {
    const a = new A(data)
    dependecy.doAnotherThing(a)
  }
}

And test:

it(('shoud doSomething') => {
  const doAnotherThingStub = stub(B.prototype, 'doAnotherThing')
  //this part does not work, just an example of what I would like to achieve
  const doAnotherThingStub = stub(A.prototype, 'constructor').returns({dataReturendFromAConstructorStub: true})
  // end of this part
  const b = new B()
  b.doSomething({})
  expect(doAnotherThingStub.calledWith({dataReturendFromAConstructorStub: true})).to.be.true
})

And my goal is to stub class A constructor. I have separate tests for class A and I do not want to test it again. I need something like stub(A.prototype,'constructor'). I have tried using proxyquire and stubs, but I was not able to inject fake constructor, either real constructor is being called or I am getting something like: A_1.default is not a constructor. Previously I had cases where I need to stub a class which I am calling directly within the test case or stub a method of the class and these are quite straight forward. But I am struggling with this case.

What would be the correct way of mocking the A?


Solution

  • Here is the unit test solution using proxyquire and sinon:

    a.ts:

    export default class A {
      private data!: string;
      constructor(data?: any) {
        if (data !== undefined) {
          this.data = data.stingValue;
        }
      }
    }
    

    b.ts:

    import A from './a';
    
    export default class B {
      public doSomething(data: any) {
        const a = new A(data);
      }
    }
    

    b.test.ts:

    import sinon from 'sinon';
    import proxyquire from 'proxyquire';
    
    describe('60152281', () => {
      it('should do something', () => {
        const aStub = sinon.stub();
        const B = proxyquire('./b', {
          './a': {
            default: aStub,
          },
        }).default;
        const b = new B();
        b.doSomething({});
        sinon.assert.calledWithExactly(aStub, {});
      });
    });
    

    Unit test results with coverage report:

      60152281
        ✓ should do something (1908ms)
    
    
      1 passing (2s)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |   66.67 |        0 |      50 |   66.67 |                   
     a.ts     |   33.33 |        0 |       0 |   33.33 | 4,5               
     b.ts     |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------