Dans Travailler efficacement avec Legacy Code , Michael Feathers affirme que
bons tests unitaires ... courir vite
et cela
Un test unitaire qui prend 1/10e de seconde pour s'exécuter est un test unitaire lent.
Je pense que ces définitions ont du sens. Je pense aussi qu'ils impliquent que vous devez garder un ensemble de Tests unitaires et un ensemble de Ces tests de code qui prennent plus de temps séparément, mais je suppose que c'est le prix que vous payez pour appeler un test unitaire uniquement s'il fonctionne (très) rapidement.
Évidemment, le problème en C++ est que pour "exécuter" votre test unitaire ( s ), vous devez:
Éditer (après un étrange vote serré): Avant d'entrer dans les détails, je vais essayer de résumer le point ici:
Comment organiser efficacement le code de test unitaire C++, afin qu'il soit à la fois efficace d'éditer le code (de test) et d'exécuter le code de test?
Le premier problème consiste alors à décider où de mettre le code de test unitaire de sorte que:
Le deuxième problème lié est alors quoi à compiler pour que le feedback soit instantané.
Options extrêmes:
Alors, comment sont gérés les tests unitaires C++ du monde réel ? Si je ne lance que ce genre de choses tous les soirs/toutes les heures, la deuxième partie n'a pas vraiment d'importance, mais la première partie, à savoir comment "coupler" le code UT au code de production, de sorte qu'il soit "naturel" pour les développeurs de garder les deux au point est toujours important, je pense. (Et si les développeurs ont le code UT au point, ils voudront l'exécuter, ce qui nous ramène à la deuxième partie .)
Histoires et expériences du monde réel appréciées !
Remarques:
Nous avons tous les tests unitaires (pour un module) dans un seul exécutable. Les tests sont regroupés. Je peux exécuter un seul test (ou certains tests) ou un groupe de tests en spécifiant un nom (test/groupe) sur la ligne de commande du lanceur de test. Le système de build peut exécuter le groupe "Build", le département de test peut exécuter "All". Le développeur peut mettre des tests dans un groupe comme "BUG1234", 1234 étant le numéro de suivi des problèmes de l'affaire sur laquelle il travaille.
Tout d'abord, je ne suis pas d'accord avec "1) Modifier votre code (de production) et votre test unitaire". Vous ne devez modifier qu'un seul à la fois, sinon si le résultat change, vous ne saurez pas lequel l'a causé.
J'aime mettre des tests unitaires dans une arborescence de répertoires qui assombrit l'arborescence principale. Si j'ai /sources/componentA/alpha/foo.cc
et /objects/componentA/beta/foo.o
, alors je veux quelque chose comme /UTest_sources/componentA/alpha/test_foo.cc
et /UTest_objects/componentA/beta/test_foo.o
. J'utilise le même arbre d'ombre pour les objets stub/mock et toutes les autres sources dont les tests ont besoin. Il y aura des cas Edge, mais ce schéma simplifie beaucoup les choses. Une bonne macro d'édition peut tirer la source de test à côté de la source du sujet sans effort. Un bon système de construction (par exemple GNUMake) peut compiler les deux et exécuter le test avec une seule commande (par exemple make test_foo
), et peut gérer un bazillion de tels processus - juste ceux dont les sources ont changé depuis leur dernier test - assez facilement (je n'ai jamais trouvé la surcharge de démarrage de ces processus être un problème, c'est O (N) ).
Dans le même cadre, vous pouvez avoir des tests à plus grande échelle (plus de tests unitaires) qui relient de nombreux objets entre eux et exécutent de nombreux tests. L'astuce consiste à trier ces tests en fonction du temps nécessaire à leur création/exécution et à les intégrer à votre programme quotidien en conséquence. Exécutez le test d'une seconde ou moins chaque fois que vous en avez envie; commencer le test de dix secondes et étirer; test de cinq minutes et faire une pause; tester une demi-heure et aller déjeuner; test de six heures et rentrez chez vous. Si vous trouvez que vous perdez beaucoup de temps, par exemple relier un énorme test après avoir changé un seul petit fichier, vous le faites mal - même si la liaison était instantanée, vous exécuteriez toujours un long test quand il n'était pas demandé.