109 votes

Pouvez-vous m'aider à comprendre le Moq Callback ?

J'utilise Moq et j'ai regardé Callback mais je n'ai pas réussi à trouver un exemple simple pour comprendre comment l'utiliser.

Avez-vous un petit extrait de travail qui explique clairement comment et quand l'utiliser ?

91voto

Ruben Bartelink Points 23945

Difficile à battre https://github.com/Moq/moq4/wiki/Quickstart

Si ce n'est pas assez clair, j'appellerais ça un bug doc...

EDIT : En réponse à votre précision...

Pour chaque méthode simulée Setup vous vous produisez, vous pouvez indiquer des choses comme :

  • contraintes sur les intrants
  • la valeur pour / la manière dont la valeur de retour (s'il y en a une) doit être dérivée

El .Callback Le mécanisme dit : "Je ne peux pas le décrire pour l'instant, mais quand une forme d'appel comme celle-ci se produit, rappelez-moi et je ferai ce qui doit être fait". Dans le cadre de la même chaîne d'appel fluide, vous pouvez contrôler le résultat à renvoyer (s'il y en a un) par l'intermédiaire de .Returns ". Dans les exemples de QS, ils font en sorte que la valeur renvoyée augmente à chaque fois.

En général, vous n'aurez pas besoin d'un mécanisme comme celui-ci très souvent (les Test Patterns de xUnit ont des termes pour les anti-modèles de l'espèce Conditional Logic In Tests), et s'il existe un moyen plus simple ou intégré pour établir ce dont vous avez besoin, il devrait être utilisé de préférence.

Partie 3 sur 4 de la série Moq de Justin Etheredge le couvre, et il y a un autre exemple de callbacks ici

Un exemple simple de rappel se trouve à l'adresse suivante Utilisation de Callbacks avec Moq poste.

4 votes

Bonjour Ruben, je suis en train d'apprendre Moq et si vous voulez, j'accumule beaucoup d'exemples pour comprendre comment faire les choses en l'utilisant. Mon problème est que je ne comprends pas quand l'utiliser. Une fois que j'aurai résolu ce problème, j'écrirai mon propre code. Si tu devais l'expliquer dans tes propres mots, quand utiliserais-tu le callback ? Merci d'avoir pris le temps de m'écouter.

22 votes

Difficile à battre [lien] ? Pas du tout. Ce lien vous montre comment pour faire des dizaines de choses différentes, mais ne vous dit pas por qué dont vous auriez besoin pour les faire. C'est un problème courant dans la documentation sur les simulacres, j'ai trouvé. Je peux compter sur les doigts de la main le nombre de bonnes explications claires de TDD + mocking que j'ai trouvées. La plupart supposent un niveau de connaissance qui, si je l'avais, je n'aurais pas besoin de lire l'article.

0 votes

@Kyralessa : Je comprends votre point de vue. Personnellement, j'avais déjà pas mal de connaissances livresques en arrivant et j'ai trouvé les trucs de démarrage rapide absolument parfaits. Malheureusement, je ne connais pas de meilleur exemple que ceux que j'ai mis en lien à la fin de l'article. Si vous en trouvez un, postez-le ici et je serai heureux de l'éditer (ou n'hésitez pas à faire du bricolage).

63voto

Jeff Hall Points 1016

Voici un exemple d'utilisation d'un callback pour tester une entité envoyée à un service de données qui gère une insertion.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Syntaxe de la méthode générique alternative :

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

Vous pouvez alors tester quelque chose comme

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");

4 votes

Dans ce cas particulier (selon que vous essayez d'exprimer des tests par rapport à l'état ou au comportement), il peut être plus propre d'utiliser un élément de type It.Is<T> dans un Mock.Verify au lieu de joncher le test de temps. Mais +1 parce que je parie qu'il y a beaucoup de gens qui travailleront mieux à partir d'un exemple.

13voto

Ohad Schneider Points 10485

Callback est simplement un moyen d'exécuter le code personnalisé que vous souhaitez lorsqu'un appel est fait à l'une des méthodes de l'objet fantaisie. Voici un exemple simple :

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

J'ai récemment rencontré un cas d'utilisation intéressant. Supposons que vous attendez des appels à votre objet fantaisie, mais qu'ils se produisent simultanément. Vous n'avez donc aucun moyen de savoir dans quel ordre ils seront appelés, mais vous voulez savoir si les appels attendus ont bien eu lieu (indépendamment de l'ordre). Vous pouvez faire quelque chose comme ceci :

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

Ne vous laissez pas abuser par le terme trompeur "avant". Returns "et "après Returns distinction ". Il s'agit simplement d'une distinction technique qui permet de savoir si votre code personnalisé s'exécutera après l'entrée en vigueur de la loi. Returns a été évalué ou avant. Aux yeux de l'appelant, les deux s'exécuteront avant que la valeur ne soit retournée. En effet, si la méthode est void -Retourner vous ne pouvez même pas appeler Returns et pourtant ça marche pareil. Pour plus d'informations, voir https://stackoverflow.com/a/28727099/67824 .

12voto

Shaun Luttin Points 1585

Il existe deux types de Callback dans Moq. L'un se produit avant le retour de l'appel ; l'autre se produit après le retour de l'appel.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

Dans les deux callbacks, on peut :

  1. inspecter les arguments de la méthode
  2. arguments de la méthode de capture
  3. changer l'état contextuel

1voto

John Carpenter Points 2455

En plus des autres bonnes réponses ici, je l'ai utilisé pour effectuer une logique avant de lancer une exception. Par exemple, j'avais besoin de stocker tous les objets qui étaient passés à une méthode pour une vérification ultérieure, et cette méthode (dans certains cas de test) devait lever une exception. Appeler .Throws(...) en Mock.Setup(...) remplace le Callback() action et ne l'appelle jamais. Cependant, en lançant une exception dans la callback, vous pouvez toujours faire toutes les bonnes choses qu'une callback a à offrir, et toujours lancer une exception.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X