7

When using sinon I just want to replace my function's return value and don't need other infos like how many time it was called. Which one of them is better?

sinon.replace(Component.prototype, 'getValue', () => 123);
const myStub = sinon.stub(Component.prototype, 'getValue');
myStub.return(123);
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Takuya HARA
  • 499
  • 1
  • 3
  • 17

1 Answers1

13

I rarely see sinon.replace being used in many projects. The advantage of using stub is you can modify the return value many times for example.

let getValueStub;

before(function() {
   getValueStub = sinon.stub(Component.prototype, 'getValue');
})

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

it('test case A if return value is 123', function() {
   getValueStub.returns(123);
   // do expectation
})

it('test case B if return value is 234', function() {
   getValueStub.returns(234);
   // do expectation
})

Meanwhile, for replace, based on Sinon documentation, you can use it only one time.

sandbox.replace(object, property, replacement);

Replaces property on object with replacement argument. Attempts to replace an already replaced value cause an exception.

replacement can be any value, including spies, stubs and fakes.

For example:

sinon.replace(Component.prototype, 'getValue', function () {
  return 123;
});

sinon.replace(Component.prototype, 'getValue', function () { // this will return error
  return 456;
});

it will return error

TypeError: Attempted to replace getValue which is already replaced

You probably can achieve the same thing like stub with sinon.replace by replacing the function with stub

getValueStub = sinon.stub();    
sinon.replace(Component.prototype, 'getValue', getValueStub);

getValueStub.returns(123); 
getValueStub.returns(456);

Still, I prefer use sinon.stub due to simplicity.

Reference:

https://sinonjs.org/releases/v7.2.2/sandbox/#sandboxreplaceobject-property-replacement

deerawan
  • 8,002
  • 5
  • 42
  • 51
  • 2
    While the simplicity claim is fair, reusing the same stub is an anti-pattern that can lead to flaky tests, if you don't clean up properly between tests, which is why we introduced the `fake`s and the `replace` methods. This is also the only way of injecting a `fake`. – oligofren Feb 08 '19 at 16:43
  • @oligofren how would you have the fake return different values for different calls (for example in a loop). The docs say that you can do anything with fakes that you can do with stubs, but I don't see how this particular use case is satisfied using fakes. – Nightwolf Feb 24 '23 at 15:32
  • 1
    @Nightwolf You just implement a custom fake. `callCount = 0, f = () => { switch(callCount++){ case 1: return 'foo'; case 2: return 'bar'; default: return callCount; } }`. This will return `0`, `"foo"`, `"bar"`, `3` on the first 4 calls. Just wrap it to have a fake: `sinon.fake(f)`; The 80% of use cases you need is in the exposed minimal API. The more exotic bits covering the last 20% you use a custom fake to do, but it let's you forget about everything but the essential API surface. The definition will be slightly longer, but your readers will at least know what the fake is doing. – oligofren Feb 26 '23 at 16:57
  • Thanks @oligofren. That's what I ended up doing. I was just hoping for a simpler interface, but at the very least, the code is quite obvious when you read it. – Nightwolf Feb 27 '23 at 20:59