Chaque test unitaire doit-il pouvoir être exécuté indépendamment des autres tests?


24

Supposons que vous ayez des tests pour deux méthodes d'une classe. La première méthode rassemble les données d'un autre niveau et les place dans une sorte de stockage indépendant du runtime (comme une table SQL), donc toutes les données traitées par ce test sont codées en dur dans le test. La deuxième méthode est chargée de prendre des données d'où la première méthode les a laissées et de les transformer d'une certaine manière (calcul, déplacement de certaines parties ailleurs, etc.).

Maintenant, cette deuxième méthode pourrait avoir des entrées codées en dur comme la première, ou on pourrait supposer que les deux tests seraient exécutés séquentiellement et pourraient reprendre là où le 1er test s'était arrêté, en prenant les données qui étaient réellement stockées par le premier test.

Si vous optiez pour la deuxième option, vous auriez vraiment une bonne idée que les deux méthodes fonctionnent bien ensemble, cependant, si le premier test échouait, tous les tests après échoueraient, ce qui retirerait l'avantage du test d'aider à isoler les bogues plus rapidement.

Si vous optiez pour la première option, chaque méthode serait isolée et testée indépendamment, mais vous ne sauriez jamais vraiment qu'elles peuvent vraiment fonctionner correctement ensemble.

Quelle est la meilleure option ici? Existe-t-il une sorte d'alternative comme avoir un seul test pour chaque méthode isolée avec codage en dur, puis des tests plus importants qui contiennent les deux méthodes en une seule?


2
Je souhaite réellement pouvoir randomiser facilement l'ordre des tests unitaires à chaque exécution. À l'heure actuelle, ils fonctionnent dans un ordre inconnu, bien que relativement fixe.
Job

Réponses:


11

Si vous optiez pour la première option, chaque méthode serait isolée et testée indépendamment, mais vous ne sauriez jamais vraiment qu'elles peuvent vraiment fonctionner correctement ensemble.

Si vos méthodes sont vraiment indépendantes, cela ne devrait pas avoir d'importance. Votre deuxième méthode devrait:

a) Fonctionne correctement lorsqu'il est présenté avec des données valides.

b) Échouer de manière sensible et cohérente lorsqu'il est présenté avec des données invalides.

De même, votre première méthode devrait faire de même. Aussi longtemps que vous gérerez les cas d'erreur, ils fonctionneront correctement ensemble.

Si vous voulez tester que les méthodes fonctionnent correctement ensemble, il s'agit de tests d'intégration, pas de tests unitaires.


27

Si les tests ne peuvent pas s'exécuter indépendamment, ce ne sont pas des tests unitaires.

Un test unitaire ne doit pas reposer sur un état externe, tel que le contenu d'une table de base de données. Il doit tester uniquement une unité de code de manière isolée.

Les tests qui modifient ou nécessitent un certain état sont valides, ils peuvent faire partie des tests d'intégration par exemple, et dans de tels cas, il est important de s'assurer que la configuration appropriée est effectuée, mais il ne s'agit pas de tests unitaires. Dans ce cas, je ne conseillerais toujours pas qu'un test nécessite qu'un autre soit exécuté. Si vous êtes dans ce cas, vous devez probablement factoriser le code requis dans une méthode de configuration séparée. Vous pouvez très bien avoir un test qui appelle ensuite simplement le code de configuration et vérifie qu'aucune exception n'est levée, par exemple, puis un autre test qui utilise activement les données configurées dans la méthode de configuration.


@Steve, donc dans cet exemple, diriez-vous: un test pour la méthode 1, un test pour la méthode 2 et un test qui exécute 1 et 2 dans le même test?
Morgan Herlocker

2
Oui. les deux premiers seraient des tests unitaires, le troisième sonne comme un test d'intégration.
Steve

si vous avez un module client et un module commandes et que la commande ne peut pas être créée sans relation avec le client. Comment allez-vous le tester indépendamment du module client: créer un enregistrement client dans la base de données avec sql (insérer dans le client) ou utiliser Customer.createCustomer (). Et à mon humble avis, utiliser le second est meilleur, car vous n'avez besoin d'aucune logique de test dans le test, mais cela ne fonctionne que si votre test sur la création de clients réussit.
Dainius

@Dainius. Dans un scénario de test unitaire, vous utilisez généralement des objets fictifs, vous devez donc transmettre un client fictif à votre module de commande. Vous avez raison en ce que vous ne voudriez pas utiliser sql dans ce cas.
Steve

il semble que dans tout scénario où la méthode B dépend de la méthode A, il y aura presque toujours une méthode C qui appelle A puis appelle B. Puisque c'est le cas, vous pouvez tester A, B et C indépendamment.
Morgan Herlocker

9

Je suis sûr qu'il semble OK en ce moment d'avoir le test unitaire B qui dépend de l'état laissé par le test unitaire B. Mais considérons un an à partir de maintenant quand vous aurez mille tests unitaires. Voulez-vous vraiment attendre dix minutes pour que votre suite de tests complète se termine à chaque fois que vous devez apporter une modification?

Cela dépend bien sûr de votre style de développement, mais si vous souhaitez avoir un espoir de développement piloté par des tests décents, dans lequel vous pouvez exécuter un test individuel plusieurs fois lors du développement d'une fonctionnalité, je vous suggère de donner à chaque test la capacité de se tenir seul.


1
+1 Raskolnikov, je n'ai pas pris en compte le fait que ce serait un énorme gain de temps plus tard lorsque j'aurais "exécuté tous les tests" plus tard.
Morgan Herlocker du

3

On dirait que vous parlez de configuration de test, qui peut être effectuée de plusieurs manières. Vous voulez une copie propre des données de test (appelées fixture) pour chaque test, donc chacune ne devrait pas dépendre les unes des autres.

Il existe plusieurs cadres qui permettent ce type de test, et des outils comme DBUnit qui vous permettent de créer et de démonter rapidement des structures de données au début et à la fin des tests et des suites de tests.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.