Search code examples
javascriptnode.jsunit-testingchaisinon

sinon wont replace dependency


I am trying to write a unit test for the class in the example below.

const DependencyClass = require('../../../../Dependency/src/index').DependencyClass;
const string = 'test';

class FirstClass {
    async getResult() {
        const dependency = new DependencyClass();
        const result = dependency.getResult(string);
        return result;
    }
}

module.exports = {
    FirstClass
};

I am trying to stub the getResult() method of the DependencyClass class so it returns a predefined value when called from my unit tests but cant figure out how to do it.

const FirstClass = require('../../lib/FirstClass ').FirstClass;

describe('FirstClass.js', function() {
    describe('getResult()', function() {
        it('throws an exception if the result is not returned', async function() {
            const firstClass = new FirstClass();
            sinon.replace(firstClass.getResult, 'DependencyClass.getResult', function() {
                    const fakeResult =
                    [
                        'test1',
                        'test2'
                    ];
                    return fakeResult;
                });

            const expectedResult =
                [
                    'test1',
                    'test2'
                ];

            const result = await firstClass.getResult();
            expect(result).to.deep.eq(expectedResult);
        });
    });
});

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

I understand that DependencyClass.getResult is not a property of the firstClass.getResult object but I am struggling to understand how sinon should be used in this context.


Solution

  • If you want to stub method getResult() from class DependencyClass, then you need to create stub from it: sinon.stub(DependencyClass.prototype, 'getResult');.

    Here the complete example.

    Note: I remove all async await, because it is unnecessary for this simple example.

    File DependencyClass.js

    // @file DependencyClass.js
    class DependencyClass {
      getResult() {
        return 'xxx';
      }
    }
    
    module.exports = { DependencyClass };
    

    File FirstClass.js

    // @file FirstClass.js
    const { DependencyClass } = require('./DependencyClass.js');
    
    const string = 'test';
    
    class FirstClass {
      getResult() {
        const dependency = new DependencyClass();
        return dependency.getResult(string);
      }
    }
    
    
    module.exports = { FirstClass };
    

    Test spec file

    // @file stackoverflow.spec.js
    const sinon = require('sinon');
    const { expect } = require('chai');
    
    const { DependencyClass } = require('./DependencyClass');
    const { FirstClass } = require('./FirstClass');
    
    describe('FirstClass.js', function () {
      describe('getResult()', function () {
        it('throws an exception if the result is not returned', function () {
          // Create fake response.
          const fakeResult = ['test1', 'test2'];
          // Create stub DependencyClass method getResult().
          const stubDependencyGetResult = sinon.stub(DependencyClass.prototype, 'getResult');
          stubDependencyGetResult.returns(fakeResult);
    
          // Initiate first class.
          const firstClass = new FirstClass();
          // Call firstClass method getResult.
          const result = firstClass.getResult();
          // Check whether the result is correct.
          expect(result).to.deep.equal(fakeResult);
          // Verify stub get called.
          expect(stubDependencyGetResult.calledOnce).to.equal(true);
          // Restore stub.
          stubDependencyGetResult.restore();
        });
      });
    });
    

    When I run it using mocha:

    $ mocha stackoverflow.spec.js 
    
    
      FirstClass.js
        getResult()
          ✓ throws an exception if the result is not returned
    
    
      1 passing (6ms)
    
    $
    

    Hope this helps.