Mocking out with Sinon.js a dependency to be injected

1.9k Views Asked by At

Having the following balanceRepository.js file.

module.exports = function(){
this.getBalance = (accountId)=>{
    throw 'NotImplementedException';
};};

And the service transactionService.js file.

module.exports = function(balanceRepo){
this.isTransactionAllowed = (amount, accountId)=>{
    const balance = balanceRepo.getBalance(accountId);
    return amount <= balance;
};};

I would like to unit test that when we call transactionService.isTransactionAllowed, it will call internally to balanceRepository.getBalance. I was expecting the following code to work.

let BalanceRepository = require('../balanceRepository');
let TransactionService = require('../transactionService');

let should = require('should');
let sinon = require('sinon');

describe('transaction service', ()=>{
   let fakeBalanceRepo = sinon.spy(BalanceRepository);
   let transactionSrv = new TransactionService(fakeBalanceRepo);

   transactionSrv.isTransactionAllowed(100, 987654321);

   it('should call getBalance', ()=>{
      fakeBalanceRepo.getBalance.should.be.called();
});});

I create a spy of the class BalanceRepository. I inject that spy object to my real implementation of TransactionService. Then, I assert that the getBalance method is called on the spy. It makes sense to me but it is not working!!

How can I inject a fake and assert that one of its methods was called?

2

There are 2 best solutions below

0
osotorrio On BEST ANSWER

This works as estus has commented.

let balanceRepo = new BalanceRepository();
let fakeGetBalance = sinon.stub(balanceRepo, 'getBalance');

let transactionSrv = new TransactionService(balanceRepo);
transactionSrv.isTransactionAllowed(100, 987654321);

it('should call getBalance', ()=>{
    fakeGetBalance.should.be.called();
});
2
Estus Flask On

sinon.spy(BalanceRepository) doesn't mean that class methods will be automatically spied (they won't).

TransactionService expects BalanceRepository instance while fakeBalanceRepo is a constructor.

If the intention is to spy on class method and not change its behaviour, it's:

   let balanceRepo = new BalanceRepository;
   sinon.spy(balanceRepo, 'isTransactionAllowed')
   let transactionSrv = new TransactionService(balanceRepo);
   transactionSrv.isTransactionAllowed(100, 987654321);
   balanceRepo.getBalance.should.be.called();