TL; DR
Écrire de bons tests utiles est difficile et a un coût élevé en C ++. Pouvez-vous des développeurs expérimentés partager votre justification sur quoi et quand tester?
Longue histoire
J'avais l'habitude de faire du développement piloté par les tests, toute mon équipe en fait, mais cela ne fonctionnait pas bien pour nous. Nous avons de nombreux tests, mais ils ne semblent jamais couvrir les cas où nous avons de réels bugs et régressions - qui se produisent généralement lorsque les unités interagissent, et non de leur comportement isolé.
C'est souvent si difficile à tester au niveau de l'unité que nous avons cessé de faire TDD (sauf pour les composants où cela accélère vraiment le développement), et avons plutôt investi plus de temps pour augmenter la couverture des tests d'intégration. Bien que les petits tests unitaires n'aient jamais détecté de vrais bogues et n'étaient essentiellement que des frais de maintenance, les tests d'intégration en valaient vraiment la peine.
Maintenant, j'ai hérité d'un nouveau projet et je me demande comment procéder pour le tester. C'est une application native C ++ / OpenGL, donc les tests d'intégration ne sont pas vraiment une option. Mais les tests unitaires en C ++ sont un peu plus difficiles qu'en Java (vous devez faire explicitement des trucs virtual
), et le programme n'est pas fortement orienté objet, donc je ne peux pas me moquer de certaines choses.
Je ne veux pas déchirer et OO-ize le tout juste pour écrire des tests pour le plaisir d'écrire des tests. Je vous demande donc: pour quoi dois-je écrire des tests? par exemple:
- Fonctions / classes que je m'attends à changer fréquemment?
- Fonctions / classes plus difficiles à tester manuellement?
- Fonctions / Classes déjà faciles à tester?
J'ai commencé à enquêter sur quelques bases de code C ++ respectueuses pour voir comment elles procèdent aux tests. En ce moment, je regarde le code source de Chromium, mais j'ai du mal à extraire leur justification de test du code. Si quelqu'un a un bon exemple ou un article sur la popularité des utilisateurs de C ++ (gars du comité, auteurs de livres, Google, Facebook, Microsoft, ...), ce serait très utile.
Mise à jour
J'ai cherché sur ce site et sur le Web depuis que j'ai écrit ceci. J'ai trouvé de bonnes choses:
- Quand est-il approprié de ne pas effectuer de test unitaire?
- /programming/109432/what-not-to-test-when-it-come-to-unit-testing
- http://junit.sourceforge.net/doc/faq/faq.htm#best
Malheureusement, tous ces éléments sont plutôt centrés sur Java / C #. L'écriture de nombreux tests en Java / C # n'est pas un gros problème, donc l'avantage surpasse généralement les coûts.
Mais comme je l'ai écrit ci-dessus, c'est plus difficile en C ++. Surtout si votre base de code n'est pas si-OO, vous devez sérieusement gâcher les choses pour obtenir une bonne couverture de test unitaire. Par exemple: l'application dont j'ai hérité a un Graphics
espace de nom qui est une fine couche au-dessus d'OpenGL. Afin de tester l'une des entités - qui utilisent toutes directement ses fonctions - je devrais transformer cela en une interface et une classe et l'injecter dans toutes les entités. Ce n'est qu'un exemple.
Donc, en répondant à cette question, gardez à l'esprit que je dois faire un investissement assez important pour écrire des tests.
la source
Réponses:
Eh bien, les tests unitaires ne sont qu'une partie. Les tests d'intégration vous aident à résoudre le problème de votre équipe. Les tests d'intégration peuvent être écrits pour toutes sortes d'applications, également pour les applications natives et OpenGL. Vous devriez consulter "Growing Object Oriented Software Guided by Tests" de Steve Freemann et Nat Pryce (par exemple http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627 ). Il vous guide pas à pas dans le développement d'une application avec interface graphique et communication réseau.
Tester un logiciel qui n'était pas piloté par les tests est une autre histoire. Consultez Michael Feathers "Working Effectiveively with Legacy Code" (http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052).
la source
C'est dommage que TDD "n'ait pas bien fonctionné pour vous". Je pense que c'est la clé pour comprendre vers qui se tourner. Revoyez et comprenez comment TDD n'a pas fonctionné, que pourriez-vous faire de mieux, pourquoi y a-t-il eu des difficultés.
Donc, bien sûr, vos tests unitaires n'ont pas détecté les bogues que vous avez trouvés. C'est un peu le point. :-) Vous n'avez pas trouvé ces bogues parce que vous les avez empêchés de se produire en premier en réfléchissant à la façon dont les interfaces devraient fonctionner et comment vous assurer qu'elles ont été testées correctement.
Pour répondre, vous vous interrogez, comme vous l'avez conclu, sur le code de test unitaire qui n'est pas conçu pour être testé est difficile. Pour le code existant, il peut être plus efficace d'utiliser un environnement de test fonctionnel ou d'intégration plutôt qu'un environnement de test unitaire. Testez l'ensemble du système en vous concentrant sur des domaines spécifiques.
Bien entendu, les nouveaux développements bénéficieront de TDD. Au fur et à mesure que de nouvelles fonctionnalités sont ajoutées, le refactoring pour TDD pourrait aider à tester le nouveau développement, tout en permettant également le développement de nouveaux tests unitaires pour les fonctions héritées.
la source
Je n'ai pas fait TDD en C ++ donc je ne peux pas commenter cela, mais vous êtes censé tester le comportement attendu de votre code. Bien que l'implémentation puisse changer, le comportement devrait (généralement?) Rester le même. Dans le monde centré sur Java \ C #, cela signifierait que vous testez uniquement les méthodes publiques, que vous écrivez des tests pour le comportement attendu et que vous le faites avant l'implémentation (ce qui est généralement mieux dit que fait :)).
la source