Autofixture: Désactiver éventuellement la mise en cache pour AutoMoq ?

Créé le 20 mai 2016  ·  14Commentaires  ·  Source: AutoFixture/AutoFixture

Lorsque vous utilisez une AutoConfiguredMoqCustomization, la valeur renvoyée par le luminaire utilisé est mise en cache et la même valeur sera renvoyée à chaque invocation (je ne sais pas si cela est fait dans MockType.ReturnsUsingContext ou ailleurs, mais je vois un commentaire à ce sujet à la ligne 104 là-bas).

Le seul moyen que j'ai trouvé pour le remplacer est de passer une instance Frozen de la maquette en question dans la méthode de test et de remplacer la configuration avec une fonction appelant le luminaire :

someMock.Setup(it => it.SomeMethodReturningAString()).Returns(() => fixture.Create<string>())

Existe-t-il un moyen plus générique/plus intelligent de configurer les simulations générées automatiquement pour invoquer l'appareil chaque fois qu'une valeur est nécessaire à partir d'AutoFixture, autre que de configurer manuellement chaque invocation ?

enhancement good first issue

Commentaire le plus utile

J'avoue que je pensais que les doubles de test étaient configurés pour rappeler dans AutoFixture afin d'obtenir une valeur de retour. AutoFixture dispose déjà d'un mécanisme de gestion de la durée de vie (via ses fonctionnalités Freeze), je trouve donc un peu surprenant que AutoConfiguredMoqCustomization implémente son propre gestionnaire de durée de vie et remplace ainsi la surface de contrôle fournie par AutoFixture.

Tous les 14 commentaires

L'idée derrière la mise en cache de la valeur du résultat était de rendre toutes les méthodes _pures_ par défaut, ce qui est considéré comme une bonne pratique.

Si le système testé s'attend à une fonction pure, mais reçoit une fonction impure, le test est susceptible d'aboutir à un faux positif. Par exemple

// This method will return the expected result *if* `GetInt` is pure.
int Double(IDependency dep) {
    return dep.GetInt() + dep.GetInt();
}

Assert.Equal(dep.GetInt * 2, Double(dep));

D'un autre côté, si le système testé n'assume pas la pureté, lui donner une fonction pure ou impure ne devrait faire aucune différence.

Par conséquent, utiliser par défaut des fonctions pures avait du sens pour moi lorsque j'ai implémenté cette fonctionnalité.

Existe-t-il un moyen plus générique/plus intelligent de configurer les simulations générées automatiquement pour invoquer l'appareil chaque fois qu'une valeur est nécessaire à partir d'AutoFixture, autre que de configurer manuellement chaque invocation ?

Si vous devez le faire pour la méthode _one_, mais sur plusieurs tests, je le mettrais dans un IConfiguration réutilisable.

Si vous voulez faire cela pour toutes les méthodes, sur plusieurs tests, vous aurez besoin d'un peu plus de travail :

  • Définissez une nouvelle implémentation de ReturnsUsingContext (IIRC, vous pouvez simplement copier l'implémentation actuelle et supprimer la ligne 104)
  • Redéfinissez MockVirtualMethodsCommand et remplacez l'appel à ReturnsUsingContext par un appel à votre nouvelle méthode.
  • Redéfinissez AutoConfiguredMoqCustomization et remplacez l'instanciation de MockVirtualMethodsCommand par une instanciation de votre nouvelle classe.

Nous pourrions également penser à un moyen de rendre ce comportement configurable, mais je ne suis pas sûr que la demande soit suffisamment élevée pour le justifier. Un tel changement ne doit pas être pris à la légère, à mon avis - une personnalisation fine peut conduire à une complexité accidentelle. @ploeh , qu'en

J'avoue que je pensais que les doubles de test étaient configurés pour rappeler dans AutoFixture afin d'obtenir une valeur de retour. AutoFixture dispose déjà d'un mécanisme de gestion de la durée de vie (via ses fonctionnalités Freeze), je trouve donc un peu surprenant que AutoConfiguredMoqCustomization implémente son propre gestionnaire de durée de vie et remplace ainsi la surface de contrôle fournie par AutoFixture.

C'est un très bon point, je n'ai jamais pensé à Freeze cette façon. Changer le comportement de la personnalisation maintenant serait un changement décisif, je crois... pensez-vous qu'il devrait être modifié dans AutoFixture v4 ?

S'agit-il d'un comportement que nous avons documenté ou « promis » d'une manière ou d'une autre dans les tests ?

Étonnamment, non. J'étais à peu près sûr d'avoir couvert cela, mais il semble que non. Au moins, je n'ai trouvé aucun test couvrant cela, et la suppression de cette ligne n'a fait échouer aucun test. Cependant, selon l'OMI, il s'agit toujours d'un comportement observable, et il y aura probablement du code qui repose sur cela...

Point juste. Pourrait-il s'agir d'une valeur de configuration que nous définissons maintenant sur une valeur, puis la changeons lorsque nous passons à AutoFixture 4 ?

D'accord. Dans ce contexte, qu'entendez-vous exactement par « valeur de configuration » ? Le porter à un const à l'intérieur de la classe MockType suffirait-il ? Par exemple, private const bool cacheReturnValues = true puis if(cacheReturnValues) /**/

C'était un peu un commentaire jetable, je l'admets, donc je ne sais pas si ce serait pratiquement possible sans trop de changements. Ce que je voulais dire, cependant, c'était ceci:

@andreasnilsen aimerait changer le comportement maintenant, mais nous craignons que ce ne soit un changement donnerions à

Lorsque nous introduisons AutoFixture 4, nous modifions la configuration par défaut, de sorte que le comportement par défaut est alors que les valeurs de retour ne sont pas mises en cache. Ou peut-être supprimons-nous simplement cette option...

Quelque chose comme un booléen cacheReturnValues pourrait être une façon de le faire, mais nous devrions permettre aux clients de changer la valeur, donc cela ne peut pas être private .

(En outre, à moins que nous ne soyons absolument certains qu'il n'y aura exactement que deux valeurs, nous devrions considérer un enum au lieu d'un bool .)

Ah, j'ai d'abord pensé que vous vouliez dire un indicateur interne facile à repérer et à modifier dans la v4.

Les deux premières approches qui me viennent à l'esprit sont :

  • Ajoutez simplement un paramètre booléen (facultatif, pour une compatibilité descendante) au constructeur de AutoConfiguredMoqCustomization , qui serait ensuite propagé à MockVirtualMethodsCommand et au MockType.ReturnsUsingContext interne. Cela semble:

    1. un peu compliqué et

    2. trop _ad hoc_. Si nous voulions ajouter plus de paramètres de configuration à la personnalisation, le constructeur deviendrait trop complexe et difficile à utiliser/maintenir.

  • Utilisez le modèle d'objet de paramètre pour résoudre le problème (ii) ci-dessus.

Je me méfie de prendre des décisions de conception que nous pourrions regretter et avec lesquelles nous pourrions être coincés plus tard, donc votre expertise/expérience dans la maintenance de ce projet serait très appréciée.

Je pensais à quelque chose comme une stratégie ...

Ah oui, bien sûr ! Je suppose que j'étais obsédé par une "valeur de configuration" et que j'ai oublié de prendre du recul.

Je suis désolé pour la réponse tardive, j'ai été submergé - je vais y jeter un œil bientôt et je reviendrai avec une proposition de design.

Récemment, nous avons effectué la refactorisation de la personnalisation pour utiliser les propriétés pour le réglage de la personnalisation. Potentiellement, cette fonctionnalité pourrait être contrôlée comme suit (trouver le meilleur nom de paramètre) :
c# new AutoMoqCustomization { CacheCallResults = false }

Sous le capot, nous pourrions mettre en œuvre cela via une stratégie différente comme celle qui a été conseillée ci-dessus.

Marquage avec une balise de saut, car cela devrait être relativement simple à mettre en œuvre.

@zvirja pourriez-vous m'aider un peu et je peux travailler sur celui-ci. Je ne sais pas par où commencer :)

@micheleissa Merci pour votre intérêt ! Je suggérerais simplement de lire le code source de AutoMoq et de le déboguer pour comprendre les mécanismes internes. C'est très petit, donc ça ne devrait pas prendre beaucoup de temps...

Si vous avez une question plus précise, n'hésitez pas

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

ecampidoglio picture ecampidoglio  ·  7Commentaires

tomasaschan picture tomasaschan  ·  3Commentaires

Ridermansb picture Ridermansb  ·  4Commentaires

Accc99 picture Accc99  ·  4Commentaires

zvirja picture zvirja  ·  8Commentaires