Quelqu'un fait-il du «vrai» TDD avec Visual-C ++, et si oui, comment fait-il? [fermé]

10

Le développement piloté par les tests implique d' écrire le test avant le code et après un certain cycle :

  • Test d'écriture
  • Vérifier le test (exécuter)
  • Écrire le code de production
  • Vérifier le test (exécuter)
  • Nettoyer le code de production
  • Vérifier le test (exécuter)

En ce qui me concerne, cela n'est possible que si votre solution de développement vous permet de basculer très rapidement entre le code de production et de test, et d'exécuter le test pour une certaine partie du code de production extrêmement rapidement.

Maintenant, bien qu'il existe de nombreux cadres de tests unitaires pour C ++ (j'utilise Bost.Test atm.), Il semble qu'il n'existe pas vraiment de solution décente (pour C ++ natif ) Visual Studio (Plugin) qui rend le TDD cycle supportable quel que soit le cadre utilisé.

"Bearable" signifie que c'est une action en un clic pour exécuter un test pour un certain fichier cpp sans avoir à configurer manuellement un projet de test séparé, etc. "Bearable" signifie également qu'un test simple démarre (liaison!) Et s'exécute très rapidement .

Alors, quels outils (plugins) et techniques existent pour rendre le cycle TDD possible pour le développement natif C ++ avec Visual Studio?

Remarque: je vais bien avec des outils gratuits ou "commerciaux".

Veuillez : Aucune recommandation-cadre. (Sauf si le framework dispose d'un plugin Visual Studio dédié et que vous souhaitez recommander le plugin.)


Modifier la note : jusqu'à présent, les réponses ont fourni des liens sur la façon d'intégrer un framework de tests unitaires dans Visual Studio. Les ressources décrivent plus ou moins comment obtenir le framework UT à compiler et lancer vos premiers tests. Ce n'est pas de cela qu'il s'agit. Je suis d'avis que pour vraiment travailler de manière productive, ayant les tests unitaires dans un manuel (!), Vcproj séparé de vos classes de production ajoutera tellement de frais généraux que TDD "n'est pas possible". Pour autant que je sache, vous n'ajoutez pas de "projets" supplémentaires à une chose Java ou C # pour activer les tests unitaires et TDD, et pour une bonne raison. Cela devrait être possible avec C ++ avec les bons outils, mais il semble (cette question concerne) qu'il existe très peu d'outils pour TDD / C ++ / VS.


Googler autour, j'ai trouvé un outil, VisualAssert , qui semble viser dans la bonne direction. Cependant, afaiks, il ne semble pas être largement utilisé (par rapport à CppUnit, Boost.Test, etc.).


Edit: Je voudrais ajouter un commentaire au contexte de cette question. Je pense que cela résume bien (en partie) le problème: (commentaire de Billy ONeal )

Visual Studio n'utilise pas de "scripts de construction" qui sont raisonnablement modifiables par l'utilisateur. Un projet produit un binaire. De plus, Java a la propriété que Java ne construit jamais un binaire complet - le binaire que vous construisez n'est qu'un ZIP des fichiers de classe. Il est donc possible de compiler séparément puis de JAR ensemble manuellement (en utilisant par exemple 7z). C ++ et C # lient tous les deux leurs binaires, donc en règle générale vous ne pouvez pas écrire un script comme ça. Le plus proche que vous pouvez obtenir est de tout compiler séparément, puis de faire deux liaisons (une pour la production, une pour les tests).

Martin Ba
la source
2
As far as I am aware, you do not add extra "projects" to a Java or C# thing to enable Unit Tests and TDD,<- Je ne pense pas que ce soit correct. Vous avez généralement plusieurs projets en C # également; vous ne voulez pas envoyer votre code de test dans votre binaire de production.
Billy ONeal
2
Je n'ai jamais vu cela géré par le framework. La génération d'un binaire nécessite un projet. Vous voulez deux binaires; une avec code de test et une avec code de production. Vous avez donc besoin de deux projets. Il n'y a aucun moyen de contourner cela.
Billy ONeal
1
@BillyONeal, dans tous mes projets (Java) sauf un, le projet contient la source principale et de test - le script de construction sélectionne ensuite les éléments à mettre dans les artefacts déployables.
Robert Mark Bram
2
@Robert: Visual Studio n'utilise pas de "scripts de construction" qui sont raisonnablement modifiables par l'utilisateur. Un projet produit un binaire. De plus, Java a la propriété que Java ne construit jamais un binaire complet - le binaire que vous construisez n'est qu'un ZIP des fichiers de classe. Il est donc possible de compiler séparément puis JAR ensemble manuellement (en utilisant par exemple 7z). C ++ et C # lient tous les deux leurs binaires, donc en règle générale vous ne pouvez pas écrire un script comme ça. Le plus proche que vous pouvez obtenir est de tout compiler séparément, puis de faire deux liaisons (une pour la production, une pour les tests).
Billy ONeal
4
Sérieusement? "Astuce: chaque test doit contenir une fonction principale et générer un exécutable." Cela semble ridiculement lent pour toute quantité raisonnable de tests. Même s'ils ne signifient qu'un seul appareil de test par exécutable, c'est toujours un conseil idiot IMO. Essayez de le faire avec des milliers de tests (pour un projet de taille moyenne) ou des centaines de milliers de tests (pour un grand projet) et vous deviendrez certainement fou.
légaliser

Réponses:

4

J'ai écrit une série de blogs en 5 parties sur la réalisation de TDD avec C ++ et Visual Studio: partie 1 , partie 2 , partie 3 , partie 4 , partie 5 .

Je ne sais pas pourquoi vous dites que vous ne faites pas de projets supplémentaires en C # pour faire TDD, car c'est ce que j'ai toujours fait avec NUnit et cela semble typique de ce que font les autres avec NUnit. La raison est simple: toujours séparer le code de test du code de production. Pour C ++ avec Visual Studio, cela signifie des projets séparés, tout comme pour C # et NUnit. D'après ce que je sais du monde Java, cela est également courant là-bas.

Évidemment, tout le monde a des idées différentes de ce qui est "supportable" pour faire du TDD. Je pratique la méthode décrite dans mon blog depuis plusieurs années et je la trouve très supportable. C ++ est un langage compilé et la compilation peut être lente lorsque le système testé est fortement couplé. Il n'y a tout simplement pas moyen de s'échapper sans refactoriser une conception plus faiblement couplée.

Mon "action en un clic" est "Build Solution". Si cela crée trop, vous pouvez toujours décharger des projets non pertinents pendant que vous travaillez, puis Build Solution ne construira que le sous-ensemble minimal de projets devant être mis à jour à la suite de vos modifications.

Certes, la nature du temps de compilation de C ++ fait que cela prend un peu plus de temps à chaque cycle du processus TDD qu'avec NUnit et C #, mais la confiance que j'obtiens de mon code C ++ bien testé en vaut la peine. Sinon, je vais passer beaucoup plus de temps dans le débogueur. Je voudrais être prudent dans votre utilisation de gmock car il peut augmenter considérablement le temps de compilation. Jusqu'à présent, je me suis surtout éloigné des «faux» objets légers et j'ai rarement besoin de la fonctionnalité complète des simulacres. Les frameworks de simulation pour C ++ sont fortement basés sur des modèles et cela peut augmenter considérablement le temps de compilation, ils doivent donc être réservés là où vous avez vraiment besoin d'une simulation et un faux ne suffit tout simplement pas.

J'ai envisagé de créer un assistant de projet de test unitaire Boost.Test pour automatiser une partie de la nature de la plaque de chaudière de la création du projet de test pour le code de production, mais après l'avoir fait quelques fois, ce n'est vraiment pas si difficile à faire manuellement.

En ce qui concerne les solutions avec de nombreux projets (150?), Il existe également des moyens d'y faire face. Une solution évidente consiste à trouver des groupes de projets connexes et à les regrouper et à commencer à les consommer / à les publier en tant qu'unité. Si vous avez vraiment besoin de reconstruire / toucher les 150 projets pour les petites modifications que vous apportez au cours d'un cycle TDD, votre code est tellement couplé de toute façon que les tests unitaires ne feront probablement pas beaucoup de différence.

En regardant le lien IDE netbeans, je trouve le plaisir d'avoir quelque chose qui analyse la sortie du test et montre une petite ligne de test dans une fenêtre avec un symbole vert ou rouge à côté de quelque chose que je pensais que je manquerais d'être venu de NUnit, mais n'a pas vraiment manqué. J'ai trouvé qu'il était plus utile que la construction échoue simplement, puis je pouvais double-cliquer dans la fenêtre des erreurs pour placer le curseur à l'emplacement de l'assertion ayant échoué.

légaliser
la source
"... je ne sais pas pourquoi vous dites que vous ne faites pas de projets supplémentaires en C # ... D'après ce que je sais du monde Java, c'est aussi courant là-bas ..." Peut-être une mauvaise compréhension de ma part. (Pour .NET au moins, parce que vous avez besoin d'un exécutable pour .NET - pour java, vous avez juste besoin des fichiers de classe, donc je ne vois pas très bien où le projet supplémentaire pourrait s'intégrer.)
Martin Ba
Je ne sais pas comment Java fonctionne avec les projets; J'y ai une expérience limitée. D'après le peu que je connais, je comprends que les projets sont un artefact de l'IDE et non de la langue. (Strictement parlant, cela est également vrai pour C #, mais je ne connais personne qui utilise simplement le compilateur de ligne de commande pour autre chose que de courts articles de blog ou des démonstrations.) Cependant, même en Java, vous gardez définitivement le code de test séparé de le code de production, ce que font des projets distincts pour vous. Je ne recommande jamais la compilation conditionnelle de C ++ pour séparer le code de production et de test.
légaliser
1
"Gardez le code de test séparé du code de production, ce que font des projets séparés pour vous" - aha! Eh bien, pas vraiment, à mon humble avis. Le "projet" séparé est une nécessité pour C ++ et .NET, car les deux doivent créer un exécutable pour exécuter quoi que ce soit et pour créer un (un) exécutable, vous avez besoin d'un (un) projet. Je suis d'accord pour garder le code de test à part (ou pas) du code de production, mais je trouve devoir ajouter un "projet" (redondant) pour générer l'exécutable de test ennuyeux. :-)
Martin Ba
1
Vous avez besoin de deux produits intégrés: code de production (bibliothèque statique, bibliothèque partagée, exécutable, etc.) et un exécutable de test. Dans Visual Studio, chaque produit créé correspond à un projet, vous avez donc besoin de deux projets. Ce n'est vraiment pas plus compliqué que ça. Le projet de test unitaire n'est PAS redondant.
légaliser
2

Je n'utilise pas Visual-C ++, mais j'exécute TDD avec C ++, en utilisant googletest et googlemock, avec QtCreator comme mon IDE. Il y a des années, j'avais une configuration similaire avec Visual-C ++ mais en utilisant un cadre de test unitaire différent.

Ce que j'ai trouvé utile, c'est de séparer le projet en quelques sous-projets.

  1. Une bibliothèque statique ou dynamique qui contient 99% du code source du projet réel.
  2. Un projet qui consiste principalement en une méthode main () pour exécuter le programme normal.
  3. Un projet de test qui contient un main () pour exécuter mon framework de test et beaucoup de fichiers contenant des tests et des objets fictifs.

Avec cette configuration, mon IDE se charge d'ajouter des fichiers à divers projets et si les dépendances sont correctement déterminées, je peux exécuter tous mes tests unitaires avec une reconstruction partielle. Je l'ai même actuellement configuré pour exécuter tous mes tests immédiatement après la construction. Jenkins, l'IC que j'utilise actuellement, s'exécute également et fournit des résultats de test et des données de couverture.

Il peut être possible d'ajouter un lanceur personnalisé dans votre IDE pour un fichier afin d'exécuter les tests unitaires pour le fichier Foo.cpp s'il vous arrivait de nommer tous les tests unitaires pour Foo sous le dispositif de test TestFoo. Comment configurer cela précisément pour Visual-C ++ Je ne suis pas sûr mais je pense que c'est possible.

Corey D
la source
Informations utiles, bien que j'irais jusqu'à appeler cela le "conseil commun" :-) ... aussi ce n'est pas vraiment faisable pour nos trucs hérités, mais ajouter des tests aux trucs hérités est quand même une douleur ( et j'aurais aimé au moins faciliter l'ajout du gréement d'essai).
Martin Ba
2

J'utilise MSTest pour tester le code C ++ natif.
Voici le grand article de blog sur cette façon: http://blogs.msdn.com/b/jsocha/archive/2010/11/19/writing-unit-tests-in-visual-studio-for-native-c. aspx

Oui, il y aura au moins deux projets - un pour l'application elle-même, un pour les tests.
Au lieu de faire un troisième projet avec une bibliothèque statique, j'ajoute simplement la source de l'application au projet de test, donc la solution ressemble à ceci:

[-] Solution 'Foo'      Foo\Foo.sln
 |-[-] Foo              Foo\Foo\Foo.vcproj
 |  |-[-] include
 |  |  |- foo.h         Foo\Foo\foo.h
 |  |  |- bar.h         Foo\Foo\bar.h
 |  |
 |  |-[-] source
 |     |- foo.cpp       Foo\Foo\foo.cpp
 |
 |-[-] Foo.Tests        Foo\Foo.Tests\Foo.Tests.vcproj
    |                        (Additional include directory: "..\Foo")
    |-[-] include
    |  |- FakeBar.h     Foo\Foo.Tests\FakeBar.h
    |
    |-[-] source
       |-[-] app
       |  |- foo.cpp    Foo\Foo\foo.cpp    -- not in Foo.Tests\
       |
       |-[-] unit-tests
          |- foo_Tests.cpp   Foo\Foo.Tests\foo_Tests.cpp
          |- bar_Tests.cpp   Foo\Foo.Tests\bar_Tests.cpp
Abyx
la source
Je trouve que l'utilisation des trucs C ++ / CLI pour les tests unitaires brouille les eaux lors du test de code C ++ natif pur. J'ai cependant utilisé NUnit pour tester le code d'application C ++ / CLI. J'ai écrit mes tests en C # et cela a très bien fonctionné. (La base de code existante était C ++ / CLI et je ne voulais pas la porter en C #.)
légaliser
De plus, si vos tests sont en C ++ / CLI, vous ne pouvez pas les exécuter sur d'autres plateformes. La plupart des endroits où j'ai utilisé C ++ avaient besoin de la capacité de compilation multiplateforme. Bien sûr, vous ne pouvez pas réutiliser le projet VS sur d'autres plates-formes, mais ce n'est pas grave d'avoir des Makefiles ou des SConscripts pour cela.
légaliser
@legalize Nous ne pouvons pas non plus réutiliser WinAPI (et COM et d'autres technologies spécifiques à Windows) sur des plates-formes non Windows.
Abyx
Oui, bien sûr, vous ne pouvez pas utiliser des technologies spécifiques à Windows sur des plates-formes non Windows. Mon observation était simplement que si vous avez du code indépendant de la plate-forme, vous ne voulez pas lier vos tests unitaires à une plate-forme particulière. Chez un ancien employeur, nous avons évalué un grand nombre de cadres et de méthodes de tests unitaires. Nous avons choisi Boost.Test parce que c'était multi-plateforme et si quelque chose devait se retrouver dans la bibliothèque standard C ++ concernant les tests unitaires, ce serait probablement Boost.Test.
légaliser
2

Peut-être un peu tard dans la journée, mais si j'ai bien lu votre question, vous cherchez des techniques pour améliorer le cycle TDD? Ce n'est pas mentionné ici, mais avez-vous regardé les événements post-build dans VS?

Nos solutions sont généralement organisées (avec les dépendances du projet illustrées) ...

MAIN-APP > LIB1, LIB2, UNIT-TEST-APP
UNIT-TEST-LIB1 > LIB1
UNIT-TEST-LIB2 > LIB2
UNIT-TEST-APP > UNIT-TEST-LIB1, UNIT-TEST-LIB2

L'événement post-build de MAIN-APP se déroulera UNIT-TEST-APP

L'événement post-build de UNIT-TEST-APP s'exécute lui-même (il suffit de mettre '$ (TargetPath)' comme commande à exécuter dans l'événement post-build).

(Cela signifie que lors de la construction de MAIN-APP, les tests unitaires peuvent s'exécuter deux fois, mais cela n'a pas vraiment été un problème dans notre cas!)

Comme mentionné, oui, il y a un peu d'effort à mettre en place cette structure, mais une fois qu'elle est là, l'ajout de tests est simple.

Il vous suffit donc de créer l'application principale et les tests unitaires s'exécuteront automatiquement!

Steve Folly
la source
1

Eh bien, je ne sais pas si cela aide, mais il y a de superbes vidéos sur TDD de Brett L. Schuchert. Malheureusement, il ne montre pas la combinaison "C ++" et "VS", mais

TDD avec C # et VS: http://vimeo.com/album/210446

TDD avec C ++ et Eclipse: http://vimeo.com/13240481

Peut-être que vous pouvez le calculer à partir de ces deux.

EDIT: la vidéo C ++ concerne l'utilisation du cadre de test CppUTest avec Eclipse, bien sûr. Quand je l'ai posté, j'ai pensé qu'il devrait être facilement adopté pour une utilisation dans VS. Alors j'ai googlé un peu et trouvé ceci:

http://schuchert.wikispaces.com/tdd.cpp.NotesOnCppUTest

qui vous donne des informations sur l'utilisation de CppUTest dans Visual Studio.

Doc Brown
la source
2
Doc - J'ai (seulement) regardé la vidéo TDD / Eclipse mais je vais voter contre celle-ci. La vidéo montre exactement ce qui ne m'intéresse pas , à savoir comment écrire du code de test unitaire. Le problème (de cette question) n'est pas d'écrire des tests unitaires, c'est comment les intégrer correctement avec votre développement de production C ++ et je ne vois pas comment ces vidéos aident ici.
Martin Ba
Bien que j'ai rétrogradé cette réponse dans le contexte de cette question, je voudrais ajouter que les vidéos sont assez belles. J'ai trouvé l'Eclipse / TDD / C ++ intéressant à regarder. Cela n'aide pas du tout ici :-)
Martin Ba
@Martin: voir ma modification.
Doc Brown
Votre effort est apprécié et bien que je ne pense pas que ce lien supplémentaire soit vraiment utile dans le contexte de cette question, je pense que je vais devoir faire quelques modifications moi-même.
Martin Ba
@Martin: ok, j'ai relu votre question et votre définition de "supportable", mais n'en attendez-vous pas un peu trop? La mise en place d'un projet de test unitaire n'est pas une solution "en un clic", mais l'effort pour écrire les tests unitaires réels l'emporte sur les ordres de grandeur, quel que soit le cadre que vous utilisez.
Doc Brown
1

Googletest
Comment intégrer avec vc ++

Vous n'avez pas besoin d'un plugin, le test n'est qu'une autre cible. Il n'y a pas de plugins pour générer des tests avec c ++, même si vous le pouviez, ce serait tester des choses inutiles comme des affectations

Martin Beckett
la source
"même si vous le pouviez, ce serait tester des trucs inutiles comme des devoirs" - qu'est-ce que ça veut dire? Pensez-vous vraiment qu'un meilleur support IDE pour les tests unitaires en C ++ ne vaut rien ??
Martin Ba
Je veux dire sur un langage comme c ++, le système ne peut pas créer automatiquement des tests pour autre chose que des déclarations évidentes
Martin Beckett
2
Pourquoi pas? Qu'est-ce qui empêche un plugin de générer automatiquement un vcprojfichier à la volée, de récupérer le fichier de test que j'ai écrit et le fichier de production référencé et d'essayer de l'exécuter? (Je rêve juste, mais ça pourrait marcher.)
Martin Ba
2
Je ne suis pas sûr de pouvoir suivre. évidemment, je dois écrire les tests moi-même. Mais les exécuter pourrait être beaucoup plus facile que d'avoir à configurer manuellement (et à maintenir!) Des fichiers de test-projet séparés.
Martin Ba
2
Non, je n'ai pas fait référence au code de test, mais plutôt à l'échafaudage projet / compilateur nécessaire pour obtenir le code de test plus "c'est" le code de production à exécuter.
Martin Ba
1

Je ne peux pas commenter les outils C ++ car je n'ai pas touché depuis environ 20 ans (dev .NET ces jours-ci) et je suppose que la plupart des outils de nos jours sont pour le code managé mais pour les techniques ...

Comme d'autres l'ont mentionné, le code de test est toujours dans un projet / assemblage complètement différent du code de production et oui, vous devez généralement maintenir ce projet vous-même, bien que certainement dans VS IDE ce ne soit pas un gros problème car vous avez souvent plusieurs projets comme une partie de votre solution de toute façon.

Le code de production est et doit être écrit un peu différemment pour TDD. Lorsque vous écrivez les tests en premier, vous devez concevoir votre code pour qu'il soit testable. C'est un tout autre sujet en soi, mais cela peut prendre du temps et sembler très frustrant au début, surtout si votre IDE / outils ne vous donne pas de retour rapide, décourager d'exécuter des outils de ligne de commande pour exécuter des tests est juste perturbateur.

Il existe de nombreuses techniques spécifiques pour rendre le code testable, mais la plupart d'entre elles se décomposent en création de petits objets qui ne font pas grand-chose, vous pouvez donc les tester de manière isolée et pouvoir injecter une version de test d'un comportement dans un environnement plus complexe. objets. Les cadres du CIO peuvent aider beaucoup ici.

Un livre que vous pourriez trouver utile est; Michael Feathers, Travailler efficacement avec Legacy Code. Cela utilise plusieurs langues dans ses exemples et peut vous aider à identifier des approches spécifiques pour adapter en toute sécurité du code / des techniques qui n'ont pas été initialement conçues pour être testables.

Petite mise en garde: j'ai bu il y a des années de l'Agile Kool-Aid: D

Chris Lee
la source
Remarque: j'ai déjà Working Effectively with Legacy Codesur mon bureau :-)
Martin Ba
0

Maven n'est pas largement utilisé en C ++ (pourtant, il est principalement utilisé pour Java mais est indépendant du langage) mais c'est un outil très puissant et il vous permet de tout garder dans le même projet (y compris les tests, en fait, c'est le recommandé approche avec Maven). Je ne le suggère que maintenant, car d'après les réponses jusqu'à présent, il semble qu'une alternative avec un plugin VS n'existe peut-être pas.

Recherche de plugins que j'ai trouvés:

http://incubator.apache.org/npanday/

mais il ne semble pas encore très mûr. Avec la configuration de Maven, tout ce que vous devez faire pour exécuter les tests est exécuté mvn testsur la ligne de commande.

Si vous êtes intéressé, vous pouvez en savoir plus ici et (l'un des) plugins de support C ++ ici (Maven a une architecture de plugin donc tout est un plugin).

Gyan aka Gary Buyn
la source
0

Recommandation de cadre: à notre bureau, nous utilisons TestDriven.NET qui s'intègre à Visual Studio. Les classes les plus instables sont écrites en C ++ / CLI, qui peuvent ensuite appeler pour exercer le code natif dont vous avez besoin pour tester. Oui, les classes C ++ / CLI vont dans leur propre assembly, donc un projet "testing" ajouté à la ou aux solutions.

Chris O
la source