Tous les tests unitaires dans un seul exécutable, ou les diviser?


12

Lorsque vous écrivez des tests pour un seul logiciel, par exemple une bibliothèque, préférez-vous compiler tous les tests unitaires en un seul, ou les séparer en plusieurs exécutables?

La raison pour laquelle je pose la question est que j'utilise actuellement CUnit pour tester une bibliothèque sur laquelle je travaille. Les tests sont divisés en suites distinctes qui sont compilées en un exécutable complet avec une sortie imprimée pour les échecs. Maintenant, le système de construction de cette bibliothèque est CMake (qui, malgré son nom, n'a pas grand-chose à voir avec CUnit), qui vient avec son propre framework de test, CTest . CTest me permet d'enregistrer une liste d'exécutables qui servent de tests.

Je me demande s'il faut utiliser CTest pour des tests automatisés. Cependant, cela nécessiterait que je divise les tests que j'ai écrits jusqu'à présent en cibles de compilation distinctes. Sinon, je ne peux pas vraiment utiliser certaines des fonctionnalités avancées de CTests, telles que l'exécution sélective de tests.

Je me rends compte qu'il s'agit plus d'une question des outils à utiliser, de leur gestion et de leurs conventions, mais à part cela, y a-t-il d'autres raisons de préférer un exécutable de test unique à des exécutables séparés? Ou vice versa?


Les séparer en exécutables séparés par classe. Chaque classe doit avoir son propre test unitaire sauf si la classe n'est pas testable unitaire et doit donc être testée indirectement par d'autres classes.
Brian

1
Si vous avez une grande bibliothèque avec des centaines de classes, chacune avec un test unitaire, le temps de construction est beaucoup plus long si vous créez un binaire complet pour chacune, par rapport à un (ou quelques) gros binaires. En outre, c'est beaucoup de makefiles à gérer, chacun avec des lignes de lien individuelles.
JBRWilkinson

Ce n'est pas si gros. Moins de 20 modules. Je suis également capable de les compiler tous avec les mêmes drapeaux, donc CMake peut générer les Makefiles sans trop de travail de ma part.
Benjamin Kloster

Réponses:


5

J'aime avoir mes tests automatisés dans des binaires individuels, ou au moins regroupés par groupe "appartient-ensemble", puis les appeler à partir d'un simple script shell (où un code de sortie non nul signale une défaillance et la sortie sur stderr peut être capturée pour enregistrer une explication). De cette façon, je conserve une flexibilité totale sur les tests - je peux exécuter des tests individuels directement à partir de la ligne de commande, je peux créer toutes sortes de scripts de fantaisie si je le souhaite, je peux les réorganiser comme bon me semble sans recompiler quoi que ce soit, etc.

Mais plus important encore, cela me permet également d'inclure des tests écrits dans différentes langues ou en utilisant différentes chaînes d'outils dans la même exécution. Par exemple, les tests unitaires que j'écris sont très probablement dans la langue principale du projet, et les exécuter est une question de construction et d'invocation des binaires; mais je veux également tester ma base de données, et je pourrais vouloir alimenter les scripts SQL directement à la base de données pour cela; Je pourrais vouloir exécuter un outil d'analyse de code statique sur mon code (même s'il ne s'agit que d'une sorte de linter). Je peux vouloir exécuter mon HTML statique via un vérificateur de validité. Je pourrais exécuter une grepcommande sur la base de code pour vérifier les constructions suspectes, les violations de style de codage ou les mots clés "red-flag". Les possibilités sont infinies - s'il peut être exécuté à partir de la ligne de commande et adhère à "l'état de sortie zéro signifie OK", je peux l'utiliser.


L'argument indépendant du langage est un très bon point, car j'ai l'intention d'implémenter des liaisons python pour la bibliothèque sur la route. Merci!
Benjamin Kloster

@tdammers: un cadre de test particulier?
JBRWilkinson

@JBRWilkinson: Juste un script shell de 30 lignes. Pour la plupart des langues que j'utilise, j'ai de petites bibliothèques pour les tâches de test courantes telles que l'exécution d'une fonction, la comparaison du résultat à une valeur attendue et le lancement lorsqu'elles ne correspondent pas. Mais n'importe quel cadre de test unitaire donné pourrait facilement être intégré dans un tel "méta système", tant qu'il peut s'exécuter à partir de la ligne de commande et signaler le succès / l'échec par son état de sortie.
tdammers

2

J'ai tendance à avoir une bibliothèque pour les tests unitaires d'une application (ou pour un ensemble de bibliothèques communément partagées). Dans cette bibliothèque, j'essaie de répliquer ou d'approximer les espaces de noms des objets testés pour les montages de test (j'utilise NUnit principalement). Cela simplifie la compilation, car dans .NET, il existe une surcharge inhérente à la construction de chaque binaire qui augmenterait le temps de génération d'une solution à 20 projets par rapport à celui d'une solution à 10 projets avec le même LOC. Les binaires de test ne sont pas distribués de toute façon, donc toute organisation des tests en binaires est pour votre propre convenance, et je trouve généralement que YAGNI s'applique ici comme n'importe où.

Maintenant, je n'ai généralement pas les considérations des tdammers; mon code est pratiquement tout dans une langue, et tout test impliquant des chaînes SQL n'est pas un test unitaire (sauf si vous testez qu'un producteur de requêtes renvoie la chaîne SQL attendue en fonction de certains critères), et je ne teste pratiquement jamais le réel UI (dans de nombreuses situations, c'est tout simplement impossible). J'utilise également une bibliothèque de tests unitaires qui est bien acceptée par des outils tiers tels que les build-bots et les plugins IDE, et donc les préoccupations concernant l'exécution de tests individuels, de suites partielles, etc. sont minimes.


1
Une question de culture, je suppose - dans un environnement .NET, je raisonnerais probablement beaucoup comme vous.
tdammers
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.