web-dev-qa-db-fra.com

Puis-je simuler des fonctions avec des arguments spécifiques en utilisant Jest?

Je voudrais me moquer d'une fonction avec Jest, mais seulement si elle est appelée avec des arguments spécifiques, par exemple:

function sum(x, y) {
  return x + y;
}

// mock sum(1, 1) to return 4
sum(1, 1) // returns 4 (mocked)
sum(1, 2) // returns 3 (not mocked)

Il existe une fonctionnalité similaire implémentée dans la bibliothèque RSpec de Ruby:

class Math
  def self.sum(x, y)
    return x + y
  end
end

allow(Math).to receive(:sum).with(1, 1).and_return(4)
Math.sum(1, 1) # returns 4 (mocked)
Math.sum(1, 2) # returns 3 (not mocked)

Ce que j'essaie de réaliser dans mes tests est un meilleur découplage, disons que je veux tester une fonction qui repose sur sum:

function sum2(x) {
  return sum(x, 2);
}

// I don't want to depend on the sum implementation in my tests, 
// so I would like to mock sum(1, 2) to be "anything I want", 
// and so be able to test:

expect(sum2(1)).toBe("anything I want");

// If this test passes, I've the guarantee that sum2(x) is returning
// sum(x, 2), but I don't have to know what sum(x, 2) should return

Je sais qu'il existe un moyen de mettre en œuvre cela en faisant quelque chose comme:

sum = jest.fn(function (x, y) {
  if (x === 1 && y === 2) {
    return "anything I want";
  } else {
    return sum(x, y);
  }
});

expect(sum2(1)).toBe("anything I want");

Mais ce serait bien si nous avions une fonction sucre pour la simplifier.

Cela vous semble-t-il raisonnable? Avons-nous déjà cette fonctionnalité dans Jest?

Merci pour vos commentaires.

26
Nícolas Iensen

J'ai trouvé cette bibliothèque qu'un de mes collègues a récemment écrit: jest-when

import { when } from 'jest-when';

const fn = jest.fn();
when(fn).calledWith(1).mockReturnValue('yay!');

const result = fn(1);
expect(result).toEqual('yay!');

Voici la bibliothèque: https://github.com/timkindberg/jest-when

19
STeve Shary

Non, il n'y a aucun moyen de le faire dans Jest pour l'instant. Vous pouvez utiliser stubs sinons pour cela. à partir des documents:

stub.withArgs (arg1 [ arg2, ...]);

Stubs la méthode uniquement pour les arguments fournis. Cela est utile pour être plus expressif dans vos affirmations, où vous pouvez accéder à l'espion avec le même appel. Il est également utile de créer un stub qui peut agir différemment en réponse à différents arguments.

"test should stub method differently based on arguments": function () {
    var callback = sinon.stub();
    callback.withArgs(42).returns(1);
    callback.withArgs(1).throws("TypeError");

    callback(); // No return value, no exception
    callback(42); // Returns 1
    callback(1); // Throws TypeError
}
9
Andreas Köberle

Vous pouvez utiliser:

const mockSum = jest.fn();

mockSum.mockImplementation((x, y) => {
  // Return whatever you want based on x and y...
});
6
Daniel Muñoz

Cela peut aider ...

J'avais quelque chose de similaire par lequel j'avais la même méthode appelée avec différents paramètres nécessitant un résultat retourné différent de l'appel tronqué/moqué. J'ai utilisé une variable avec une liste de fonctions lorsque j'ai fait un appel au service simulé, je prends la fonction en haut de la file d'attente et exécute la fonction. Cela nécessite de connaître l'ordre d'exécution que vous testez et ne gère pas vraiment la variation de la réponse par argument, mais m'a permis de contourner la restriction en plaisantant.

var mockedQueue = [];
mockedQueue.Push(() => {return 'A';})
mockedQueue.Push(() => {return 'B';})

service.invoke = jest.fn(()=>{
    serviceFunctionToCall = mockedQueue.shift();
    return serviceFunctionToCall();
})
2
Adam