web-dev-qa-db-fra.com

Sinon, le stub withArgs peut correspondre à certains mais pas à tous les arguments

J'ai une fonction que je stubbing qui est appelée avec plusieurs arguments. Je veux vérifier juste le premier argument. Le reste est une fonction de rappel, donc je veux les laisser seuls. Ainsi, je pourrais avoir les 2 appels suivants, en utilisant ajax comme exemple:

method.get = sinon.stub();
method.get(25,function(){/* success callback */},function(){/* error callback */});         
method.get(10,function(){/* success callback */},function(){/* error callback */});

Je ne peux pas utiliser method.get.calls... Car cela ne fait pas la différence entre le premier get(25) et le second get(10). Mais si j'utilise method.get.withArgs(25).calls..., cela ne correspond pas non plus, car withArgs() correspond à tous arguments, ce qui ne fonctionne pas (et ne pourrait jamais, avec des rappels comme celui-ci ).

Comment puis-je obtenir des stubs sinon pour vérifier et définir des réponses basées uniquement sur le premier argument?

53
deitch

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

Vous pouvez utiliser sinon.match.any:

method.get.withArgs(25, sinon.match.any, sinon.match.any); 
93
Andrew Radford

Si vous voulez simplement vérifier le premier argument que vous pouvez utiliser

method.get.withArgs(25).calledOnce

ou

method.get.calledWith(25)
1
igor

Solution

withArgs peut être utilisé pour faire correspondre certains mais pas tous les arguments.

Plus précisément, method.get.withArgs(25) will vérifie juste le premier argument .


Correction

Ceci est une erreur:

withArgs() correspond à tous les arguments


Détails

Lorsque withArgs est appelé, il se souvient des arguments qui lui ont été transmis ici comme matchingArguments.

Ensuite, lorsque le stub est appelé, il obtient tous les faux correspondants ici .

matchingFakes est appelé sans second paramètre, il renvoie donc tous les faux qui ont matchingArgumentsqui correspondent aux arguments passés au stub début à l'index 0 jusqu'à la longueur de matchingArguments . Cela signifie qu'un faux correspondra lorsque son matchingArguments correspondra au début des arguments passés même s'il y a des arguments supplémentaires.

Tout faux correspondant est alors trié par matchingArguments.length et celui qui correspond au plus d'arguments est celui qui est invoqué .


Le test suivant confirme ce comportement et passe avec sinon version 1.1.0 depuis 7 ans, version 1.14.0 à partir du moment où cette question a été posée, et la version actuelle 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

});
1

cette méthode fonctionne très bien avec les espions si vous voulez vérifier un seul argument parmi plusieurs

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

Cependant, je ne comprends pas pourquoi vous utilisez des talons ici. Si vous voulez simplement vérifier comment la fonction est appelée, vous devez utiliser un espion. Si vous voulez vérifier comment on l'appelle ET changer son comportement (ex: bloquer les appels ajax), vous devez utiliser une maquette.

Les simulateurs Sinon ont leur propre façon de vérifier les choses. La seule façon que je connaisse pour votre cas serait d'utiliser sinon.match.many pour les arguments que vous ne voulez pas vérifier:

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 () procédera au test ET réinitialisera la maquette pour d'autres tests, en cas d'utilisation d'un espion ou d'un talon, vous devez le faire manuellement avec restore () ou reset () après chaque test

PD: désolé pour la syntaxe TypeScript ici: p

1
Florent Arlandis