Can sinon stub withArgs match some but not all arguments

前端 未结 4 1497
慢半拍i
慢半拍i 2021-01-31 13:33

I have a function I am stubbing that gets called with multiple arguments. I want to check just the first argument. The rest are callback function, so I want to

相关标签:
4条回答
  • 2021-01-31 13:43

    https://sinonjs.org/releases/latest/matchers/#sinonmatchany

    You can use sinon.match.any:

    method.get.withArgs(25, sinon.match.any, sinon.match.any); 
    
    0 讨论(0)
  • 2021-01-31 13:43

    If you just want to check the first argument you can use

    method.get.withArgs(25).calledOnce
    

    or

    method.get.calledWith(25)
    
    0 讨论(0)
  • 2021-01-31 13:45

    Solution

    withArgs can be used to match some but not all the arguments.

    Specifically, method.get.withArgs(25) will check just the first argument.


    Correction

    This is incorrect:

    withArgs() matches all arguments


    Details

    When withArgs is called it remembers the arguments it was passed here as matchingArguments.

    Then when the stub is called it gets all matching fakes here.

    matchingFakes is called without a second parameter so it returns all fakes that have matchingArguments that match the arguments passed to the stub starting at index 0 up to the length of matchingArguments. This means that a fake will match when its matchingArguments match the beginning of the arguments passed even if there are additional arguments.

    Any matching fakes are then sorted by matchingArguments.length and the one that matches the most arguments is the one that is invoked.


    The following test confirms this behavior and passes with sinon version 1.1.0 from 7 years ago, version 1.14.0 from the time this question was asked, and the current version 6.3.5:

    import * as sinon from 'sinon';
    
    test('withArgs', () => {
    
      const stub = sinon.stub();
    
      stub.withArgs(25).returns('first arg is 25!');
      stub.returns('default response');
    
      expect(stub(25)).toBe('first arg is 25!');  // SUCCESS
      expect(stub(25, function () { }, function () { })).toBe('first arg is 25!');  // SUCCESS
      expect(stub(10, function () { }, function () { })).toBe('default response');  // SUCCESS
    
    });
    
    0 讨论(0)
  • 2021-01-31 13:53

    this method works very well with spies if you want to check only one argument among many

    it('should check only first argument', function ():void {
                myFunction('foo', 'bar', baz');
                expect(myFunctionSpy.firstCall.args[0]).to.equal('foo');
            });
    

    However I don't understand why you are using stubs here. If you just want to check how the function is called you should use a spy. If you want to check how it's called AND change it's behaviour (ex: blocking ajax calls) then you should use a mock.

    Sinon mocks have their own way of checking stuff. The only way I know for your case would be to use sinon.match.many for the arguments you don't want to check:

    it('should check only first argument', async function (): Promise<void> {
                    mock.expects('myFunction').withExactArgs('foo', sinon.match.any, sinon.match.any).returns('foo');
                    await myFunction('foo', 'bar', baz');
                    mock.verify();
                });
    

    mock.verify() will proceed to the test AND reset the mock for other tests, in case of using a spy or a stub you should do it mannually with restore() or reset() after each test

    PD: sorry about TypeScript syntax here :p

    0 讨论(0)
提交回复
热议问题