web-dev-qa-db-fra.com

Plusieurs assertions sont-elles mauvaises dans un test unitaire? Même si enchaîner?

Y a-t-il quelque chose qui cloche dans la vérification de tant de choses dans ce test unitaire?

ActualModel = ActualResult.AssertViewRendered()        // check 1
                          .ForView("Index")            // check 2
                          .WithViewData<List<Page>>(); // check 3

CollectionAssert.AreEqual(Expected, ActualModel);      // check 4

Les objectifs principaux de ce test sont de vérifier que la vue correcte est renvoyée (contrôle 2) et qu'elle contient les bonnes données (contrôle 4).

Est-ce que je gagnerais quelque chose en divisant cela en plusieurs tests? Je suis tout au sujet de bien faire les choses, mais je ne vais pas diviser les choses si cela n'a pas de valeur pratique.

Je suis assez novice en test unitaire, alors soyez gentil.

39
Michael Haren

Comme d'autres l'ont fait remarquer, il est préférable de s'en tenir à une assertion dans chaque test afin d'éviter de perdre des informations. Si la première assertion échoue, vous ne savez pas si les dernières échoueraient également. Vous devez résoudre le problème avec moins d’informations, ce qui pourrait être plus difficile.

Une très bonne référence est celle de Roy Osherove Art of Unit Testing - si vous voulez bien démarrer avec les tests unitaires, vous pourriez faire bien pire que de commencer ici.

29
Bevan

Notant pour les futurs lecteurs que cette question et son duplicata Est-ce une mauvaise pratique d'avoir plus d'une assertion dans un test unitaire? j'ai des opinions majoritaires opposées, lisez-les et décidez-vous vous-même.

Mon expérience est que le quantum de test le plus utile n’est pas l’affirmation, mais le scénario - c’est-à-dire qu’il devrait exister un test unitaire pour un ensemble donné de conditions initiales et d’appel de méthode, avec autant d’assertions nécessaires pour affirmer la conditions finales attendues. Avoir un test unitaire par assertion conduit à une configuration dupliquée ou à des solutions de contournement tortueuses pour éviter la duplication (comme les terribles contextes rspec profondément imbriqués que je vois de plus en plus ces derniers temps). Il multiplie également les tests, ce qui ralentit considérablement votre suite.

12

Tant que chaque assertion a un message d'échec d'identification unique et unique, vous devriez être bon et éviter les problèmes liés à Assertion Roulette car il ne sera pas difficile de savoir quel test a échoué. Utiliser le bon sens.

8
John K

J'ai trouvé un argument différent à cette question (du moins pour moi):

L’utilisation de plusieurs assertions est acceptable s’ils testent la même chose.

Par exemple, ça va:

Assert.IsNotNull(value);
Assert.AreEqual(0, value.Count);

Pourquoi? - parce que ces deux affirmations ne cachent pas l'intention du test. Si la première assertion échoue, cela signifie que la seconde échouera aussi. Et en effet, si nous supprimons la première assertion, la deuxième assertion échoue (avec une exception de référence nulle - !!!) quand la variable value est nulle. Si ce n'était pas le cas, nous ne devrions pas associer ces deux affirmations.

Donc, c'est faux:

Assert.IsNotNull(value1);
Assert.IsNotNull(value2);

Comme je l'ai mentionné ci-dessus, si la première affirmation échoue, il n'y a aucune indication claire concernant la deuxième affirmation - nous voudrions toujours savoir ce qu'il advient de la deuxième ( même si la première échoue ). Donc, pour cette raison, ces deux assertions appartiennent à deux tests unitaires différents.

Conclusion: mettre une ou plusieurs assertions, lorsque cela est fait correctement , devient la question de la préférence - si nous voulons voir des exceptions d'assertion dans les résultats du test, ou voulons-nous voir d'autres exceptions aussi en particulier cas.

7
Tengiz

Il est préférable de s'en tenir à un seul assert dans chaque test pour éviter Assertion Roulette .

Si vous devez configurer le même scénario pour tester plusieurs conditions sur des locaux identiques, il est préférable d'extraire le code de configuration dans une méthode d'assistance partagée, puis d'écrire plusieurs tests qui appellent cette méthode d'assistance.

Cela garantit que chaque cas de test teste une seule chose.

Comme toujours, il existe des exceptions à cette règle, mais puisque vous êtes nouveau aux tests unitaires, je vous recommande de vous en tenir à la règle une assertion par test unitaire jusqu'à ce que vous ayez appris quand c'est bien de s'écarter.

2
Mark Seemann

Je sais que c'est une vieille question, mais je pensais ajouter mon mot.

En général, j'aurais le moins d'assertions possibles dans chaque cas test. On peut souvent écrire des tests pour éviter d’avoir beaucoup d’assertions différentes.

Supposons que j'ai des tests unitaires pour une méthode qui crée une salutation (par exemple, M. Smith) à partir des composants d'un nom. Je veux vérifier cela avec un grand nombre de scénarios différents, il n'est pas nécessaire d'avoir un test séparé pour chacun.

Compte tenu du code suivant, il existe de nombreuses assertions différentes. Quand ils échouent, vous pouvez les corriger un par un jusqu'à ce que les affirmations s'arrêtent.

Assert.AreEqual("Mr Smith", GetSalutation("Mr", "J", "Smith"));
Assert.AreEqual("Mr Smith", GetSalutation("Mr", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "J", "Smith"));

Une alternative à cela est de garder un nombre de problèmes et de l'affirmer à la fin.

int errorCount = 0;
string result;

result = GetSalutation("Mr", "J", "Smith");
if (result == "Mr Smith")
    errorCount++;

result = GetSalutation("Mr", "John", "Smith");
if (result == "Mr Smith")
    errorCount++;

Assert.AreEqual(0, errorCount);

En situation réelle, j'ajouterais probablement quelques commandes Trace pour écrire les détails des tests individuels qui ont échoué dans la fenêtre de sortie.

0
timbo