Comment faire dépendre un test des résultats d'un autre test?


13

Disons qu'il existe une classe utilitaire qui fournit des méthodes statiques courantes utilisées partout dans votre code par de nombreuses autres classes.

Comment concevriez-vous vos tests unitaires pour les consommateurs de l'utilitaire afin que leurs tests échouent si l'un des tests d'utilité ne réussit pas? Pouvez-vous le faire ou devez-vous vérifier vous-même si les tests de classe d'utilité sont tous verts?

Par exemple, j'ai un utilitaire de séparation de messages qui est utilisé (ou plutôt sa sortie) par un analyseur de messages. Je voudrais être sûr que le séparateur de messages fonctionne correctement avant que l'analyseur de messages ne soit testé.

J'ai écrit des tests pour les deux, mais existe-t-il un moyen de les lier et de faire dépendre un test du résultat d'un autre test?

Je n'ai pas trouvé de balise appropriée pour cela, mais j'utilise le moteur de test unitaire de Visual Studio.


1
Je comprends que l'analyseur ne fonctionne pas correctement si l'utilitaire échoue. Mais si vous exécutez vos tests, vous verrez que les tests d'utilité échouent. Pourquoi voulez-vous que d'autres tests échouent également?
Eugen Martynov

1
Je n'ai jamais entendu parler de quelqu'un qui voulait ça avant. Qu'essayez-vous d'atteindre?
Esben Skov Pedersen


J'utilise certaines des fonctions de l'utilitaire pour préparer les données pour les tests de l'analyseur, je voudrais donc être absolument sûr que l'utilitaire fonctionne correctement avant de tester quoi que ce soit d'autre.
t3chb0t

3
@ t3chb0t Si vous voulez vous assurer que votre utilitaire fonctionne, vous devez écrire des tests unitaires pour vérifier votre utilitaire. Les tests unitaires doivent être atomiques. Vous voulez seulement qu'ils testent un seul composant.
maple_shaft

Réponses:


11

Il est inutile de vous assurer que chaque défaut de votre système déclenche exactement un test.

Une suite de tests a un seul travail: vérifier qu'il n'y a pas de défauts connus. S'il y a un défaut, peu importe si un test échoue ou 10. Si vous vous habituez à l'échec de votre suite de tests, si vous essayez d'évaluer à quel point votre programme est "mauvais" en comptant les tests qui échouent, vous n'êtes pas en utilisant les tests de régression de la bonne façon. La suite de tests devrait passer tous tests avant de publier du code.

La seule raison valable pour sauter des tests est s'ils testent des fonctionnalités incomplètes et prennent un temps excessif que vous pourriez mettre à mieux utiliser lors de la mise en œuvre de la chose qu'ils sont censés tester. (Ce n'est un problème que si vous ne pratiquez pas un développement piloté par les tests strict, mais c'est un choix valide, après tout.)

Sinon, ne vous embêtez pas à essayer de faire de votre suite de tests un indicateur vous indiquant précisément ce qui ne va pas. Ce ne sera jamais exact, et ce n'est pas censé l'être. C'est censé vous empêcher de faire deux fois la même erreur, c'est tout.


8

Cela dépend de votre outillage, mais vous ne pouvez probablement pas (et ne devriez pas)

Quelques frameworks de tests unitaires (prenez PHPUnit par exemple) vous permettent de «chaîner» les tests de sorte qu'un test échoué à un niveau n'exécute pas d'autres tests. Cependant, je doute que cela résoudra votre problème pour cette situation.

Le fait de ne pas permettre l'exécution garantie d'un ordre de test force les tests à être isolés les uns des autres et est généralement considéré comme une bonne chose. Imaginez ce qui se passerait si les tests s'exécutaient non seulement eux-mêmes, mais fournissaient également des données sur lesquelles d'autres tests pourraient fonctionner ...

Vous pouvez placer ces méthodes utilitaires dans une solution ou une catégorie de test distincte. Assurez-vous qu'ils «se démarquent» visuellement dans votre lanceur de test, ou que cette catégorie s'exécute en premier et n'exécute aucun autre test si les tests de cette catégorie échouent *. Lorsqu'un de ces tests échoue, l'échec se répercutera probablement sur tous les tests et vous devez vous assurer que la personne qui exécute les tests sait commencer par corriger ces tests défaillants avant tout. Il en va de même pour les tests unitaires et les tests d'intégration. Si un Unittest échoue, il se mettra en cascade et provoquera toutes sortes de chaos dans les tests d'intégration. Tout le monde sait que lorsque les tests Unit AND Integration échouent, vous commencez par vérifier les Unittests ...

* Avec une construction automatisée ou un script de test, vous pouvez d'abord exécuter cette catégorie, vérifier le résultat et exécuter les autres tests uniquement si ce premier lot de tests réussit.


5

Essayez de garder votre test unitaire atomique. N'oubliez pas que le code de test automatisé fait également partie de votre base de code, mais n'est pas lui-même en cours de test, alors gardez-le aussi simple et évident que possible.

Pour répondre plus directement à votre question, il n'y a aucune garantie quant à l'ordre d'exécution des tests, il n'y a donc aucun moyen de garantir que votre test d'utilité réussit avant que vos autres tests soient exécutés. Il n'y a donc aucun moyen garanti d'atteindre ce que vous voulez tout en ayant une seule suite de tests pour tous vos tests.

Vous pouvez déplacer les utilitaires vers leur propre solution et ajouter une référence à sa DLL résultante dans votre projet actuel.


4

Dans un résumé, vous ne voulez pas utiliser d'outils / techniques pour faire des choses autres que ce à quoi ils sont destinés.

Ce que vous essayez de faire ressemble à une préoccupation qui pourrait être facilement résolue avec une pratique de CI (intégration continue).

De cette façon, vous pouvez conserver vos tests atomiques comme déjà suggéré et laisser le CI se charger de vérifier vos tests.

Si des tests échouent, vous pouvez le définir de sorte qu'il ne permette pas à votre code d'être publié.


4

J'ai l'habitude d'essayer toujours de différencier le code au niveau de l'application du code au niveau du framework, j'ai donc rencontré le problème que vous décrivez assez souvent: vous voulez généralement que tout le code au niveau du framework soit testé avant que n'importe quel code au niveau de l'application commence à être testé . De plus, même dans le code au niveau du framework, il y a généralement des modules de framework fondamentaux qui sont utilisés par tous les autres modules de framework, et si quelque chose échoue dans les fondamentaux, il n'y a vraiment aucun intérêt à tester autre chose.

Malheureusement, les fournisseurs de frameworks de test ont tendance à avoir des idées quelque peu rigides sur la façon dont leurs créations sont censées être utilisées, et sont plutôt protecteurs de ces idées, tandis que les personnes qui utilisent leurs frameworks ont tendance à accepter l'utilisation prévue sans remettre en question. C'est problématique, car cela étouffe l'expérimentation et l'innovation. Je ne sais pas pour tout le monde, mais je préférerais avoir la liberté d'essayer de faire quelque chose d'une manière étrange, et voir par moi-même si les résultats sont meilleurs ou pires que la manière établie, plutôt que de ne pas avoir la liberté de faire les choses à ma façon en premier lieu.

Donc, à mon avis, les dépendances de test seraient une chose géniale à avoir, et au lieu de cela, la possibilité de spécifier l'ordre dans lequel les tests seront exécutés serait la prochaine meilleure chose.

Le seul moyen que j'ai trouvé pour résoudre le problème de la commande des tests est de nommer soigneusement, afin d'exploiter la tendance des frameworks de test à exécuter des tests dans l'ordre alphabétique.

Je ne sais pas comment cela fonctionne dans Visual Studio, car je n'ai encore rien fait impliquant des tests approfondis avec C #, mais du côté Java du monde, cela fonctionne comme suit: sous le dossier source d'un projet, nous avons généralement deux sous-dossiers, un appelé "principal", contenant le code de production, et un appelé "test", contenant le code de test. Sous "principal", nous avons une hiérarchie de dossiers qui correspond exactement à la hiérarchie des packages de notre code source. Les packages Java correspondent grosso modo aux espaces de noms C #. C # ne vous oblige pas à faire correspondre la hiérarchie des dossiers à la hiérarchie de l'espace de noms, mais il est conseillé de le faire.

Maintenant, ce que les gens font habituellement dans le monde Java, c'est que sous le dossier "test", ils reflètent la hiérarchie des dossiers trouvée sous le dossier "principal", de sorte que chaque test réside dans le même package que la classe qu'il teste. La raison derrière cela est que, souvent, la classe testing doit accéder aux membres privés du package de la classe testée, de sorte que la classe testing doit être dans le même package que la classe testée. Du côté C # du monde, la visibilité locale de l'espace de noms n'existe pas, il n'y a donc aucune raison de refléter les hiérarchies de dossiers, mais je pense que les programmeurs C # suivent plus ou moins la même discipline dans la structuration de leurs dossiers.

Dans tous les cas, je trouve erronée toute cette idée de permettre aux classes de test d'avoir accès aux membres package-local des classes sous test, car j'ai tendance à tester les interfaces, pas les implémentations. Ainsi, la hiérarchie des dossiers de mes tests n'a pas à refléter la hiérarchie des dossiers de mon code de production.

Donc, ce que je fais, c'est que je nomme les dossiers (c'est-à-dire les packages) de mes tests comme suit:

t001_SomeSubsystem
t002_SomeOtherSubsystem
t003_AndYetAnotherSubsystem
...

Cela garantit que tous les tests de "SomeSubsystem" seront exécutés avant tous les tests de "SomeOtherSubsystem", qui à leur tour seront tous exécutés avant tous les tests de "AndYetAnotherSubsystem", etc., et ainsi de suite.

Dans un dossier, les fichiers de test individuels sont nommés comme suit:

T001_ThisTest.java
T002_ThatTest.java
T003_TheOtherTest.java

Bien sûr, il est très utile que les IDE modernes disposent de puissantes capacités de refactorisation qui vous permettent de renommer des packages entiers (et tous les sous-packages, et tout le code qui les référence) en quelques clics et touches.


2
I don't know about everyone else, but I would prefer to have the freedom to try to do something in an odd way, and see for myself whether the results are better or worse++ compagnon. Je ne sais pas si j'aime la solution, mais j'aime l'attitude que vous y avez affichée.
RubberDuck
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.