J'ai une classe que je teste. La classe a une fonction:apply(List<IRule> rules, List<ITarget> targets);
Dans un test, je veux m'assurer que chaque cible a été passée à une règle, à la:
rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));
Il me semble que se limiter à une seule affirmation serait tout à fait le hobgoblin . Ai-je raison dans cette hypothèse, ou y a-t-il une autre façon d'affirmer que chaque cible a en fait été testée?
unit-testing
code-quality
Wayne Werner
la source
la source
Réponses:
Les trois assertions sont essentiellement un test. Vous testez le comportement d'une méthode sur une collection, pour vous assurer que chaque élément a été un paramètre pour un appel spécifique (c'est-à-dire que chaque élément a été traité correctement).
La configuration des données trois fois et selon trois méthodes différentes est un gaspillage et moins lisible que l'alternative d'avoir plusieurs assertions.
La "règle" d'assertion unique consiste davantage à effectuer des assertions de différents types dans les mêmes méthodes (essentiellement des tests de choses différentes), ce qui ne s'applique pas vraiment dans ce cas, où vous testez un seul comportement.
la source
Je pense que cette affirmation par règle de test existe pour garder vos tests concentrés sur un problème. Si vous testez 20 choses en un seul test, il est vraiment difficile de dire quelle est votre couverture. Vous savez que cela cause un problème lorsque vous ne pouvez pas nommer la méthode de test sans le mot et en lui. Par exemple, si votre méthode de test est nommée avec plus de précision
testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur()
, vous testez probablement trop dans un seul test.Dans votre cas, je pense qu'il est probablement correct d'affirmer trois fois. Si vous souhaitez rendre votre code plus lisible, vous pouvez extraire ces trois assertions dans une méthode nommée
assertWasCalledOnTargets(...)
.la source
Pour votre exemple particulier, vous pouvez vous en sortir avec "une" déclaration assert si vous faites quelque chose comme:
C'est ce que je fais pour éviter de me sentir coupable d'avoir plusieurs assertions en un seul test.
la source
J'ai aussi eu du mal avec celui-ci.
Le puriste (en moi) insiste sur une assertion par test donc je saurai * exactement * où les choses ont explosé.
Et puis je me retrouve à couper / coller beaucoup du même code de configuration de test redondant. Après la troisième ou quatrième couche de cela, vous commencez à dire "Oy! Assez!"
Mon compromis a été de trouver les aspects qui ne "cassent" jamais. Et je vais superposer ces pièces ensemble, puis ajouter un nouvel élément qui pourrait se briser. Juste pour être clair, superposer plusieurs zones volatiles en un seul test serait une violation de ce compromis.
la source
Assume
. Je viens de l'apprendre aujourd'hui.Si le code de configuration de
target1
est différent du code de configuration detarget2
, ce type de coupe d'angle a tendance à conduire à un code d'initialisation de test trop long. Ceci est à son tour soit un gâchis ou finit par être refactorisé et réutilisé. Si vos tests sont suffisamment complexes pour justifier leur refactorisation, votre test teste probablement plus d'une chose.Si le code de configuration pour chaque cible est essentiellement le même, la division de votre test en plusieurs tests individuels est probablement exagérée.
Si
target1
ettarget2
sont différentes implémentations de la même interface, vous devez plutôt ajouter un test unitaire à l'interface (et permettre à votre infrastructure de test de générer un test pour chaque implémentation de cette interface).la source