J'essaie de comprendre TDD, en particulier la partie développement. J'ai consulté des livres, mais ceux que j'ai trouvés abordent principalement la partie relative aux tests: l'histoire de NUnit, pourquoi les tests sont bons, Red / Green / Refactor et la création d'un calculateur de cordes.
Bien, mais c'est "juste" des tests unitaires, pas TDD. Plus précisément, je ne comprends pas comment TDD m'aide à obtenir une bonne conception si j'ai besoin d'une conception pour commencer à la tester.
Pour illustrer, imaginez ces 3 exigences:
- Un catalogue doit avoir une liste de produits
- Le catalogue doit rappeler quels produits un utilisateur a vus
- Les utilisateurs devraient pouvoir rechercher un produit
À ce stade, de nombreux livres tirent un lapin magique d'un chapeau et se plongent simplement dans «Test du produit», mais ils n'expliquent pas comment ils en sont venus à la conclusion qu'il existe un produit «ProductService». C’est la partie "Développement" de TDD que j’essaie de comprendre.
Il doit exister une conception existante, mais des éléments extérieurs aux services de l'entité (c'est-à-dire: il existe un produit, il doit donc exister un produitService) sont introuvables. Par exemple, la deuxième condition nécessite que Utilisateur, mais où puis-je mettre la fonctionnalité à rappeler? Et la fonction de recherche est-elle une fonctionnalité de ProductService ou un service de recherche distinct? Comment saurais-je lequel je devrais choisir?)
Selon SOLID , il me faudrait un UserService, mais si je conçois un système sans TDD, je risque de me retrouver avec toute une panoplie de services à méthode unique. Le TDD n’a-t-il pas pour but de me faire découvrir mon design?
Je suis un développeur .net, mais les ressources Java pourraient également fonctionner. Je pense qu'il ne semble pas exister de véritable exemple d'application ou de livre traitant d'une application métier réelle. Quelqu'un peut-il fournir un exemple clair illustrant le processus de création d'une conception à l'aide de TDD?
Réponses:
L'idée du TDD est de commencer par les tests et de travailler à partir de cela. Ainsi, pour prendre votre exemple de "Un catalogue a besoin d'une liste de produits" peut être considéré comme ayant le test "Rechercher des produits dans le catalogue" et il s'agit donc du premier test. Maintenant, qu'est-ce qui tient un catalogue? Que tient un produit? Ce sont les pièces suivantes et l’idée est d’obtenir quelques éléments qui ressembleraient à un ProductService qui naîtrait de la réussite de ce premier test.
L’idée de TDD est de commencer par un test, puis d’écrire le code qui le fait passer comme premier point. Les tests unitaires font partie de cela, mais vous ne regardez pas l'image globale qui est formée en commençant par les tests, puis en écrivant le code afin qu'il n'y ait pas d'ignorance à ce stade car il n'y a pas encore de code.
Didacticiel de développement piloté par les tests, où les diapositives 20 à 22 sont les plus importantes. L'idée est de savoir ce que la fonctionnalité doit faire en conséquence, rédigez un test et construisez ensuite une solution. La conception dépendra de ce qui est requis, cela peut être simple ou non. Un point clé est d’utiliser TDD dès le départ plutôt que d’essayer d’introduire tardivement dans un projet. Si vous commencez d'abord par des tests, cela peut aider et vaut probablement la peine d'être noté dans un sens. Si vous essayez d'ajouter les tests plus tard, cela devient un élément qui peut être différé ou retardé. Les dernières diapositives peuvent également être utiles.
Le principal avantage de TDD est qu’en commençant par les tests, vous n’êtes pas bloqué dans une conception au départ. L’idée est donc de construire les tests et de créer le code qui passera ces tests en tant que méthodologie de développement. Un gros design en amont peut poser des problèmes car cela donne l’idée de verrouiller les choses en place, ce qui rend le système en cours de construction moins agile au final.
Robert Harvey a ajouté ceci dans les commentaires, ce qui mérite d'être mentionné dans la réponse:
la source
Pour ce que ça vaut, TDD m'aide à obtenir le meilleur design plus rapidement que ne pas le faire. Je viendrais probablement au meilleur design avec ou sans celui-ci. Mais le temps que j'aurais passé à y réfléchir et à essayer de comprendre le code revient à écrire des tests. Et c'est moins de temps. Pour moi. Pas pour tout le monde. Et, même si cela prenait le même temps, cela me laisserait une série de tests, ce qui rendrait le refactoring plus sûr, conduisant à un code encore meilleur sur toute la ligne.
Comment ça se passe?
Premièrement, cela m'encourage à penser à chaque classe en tant que service à un code client. Un meilleur code provient de la réflexion sur la manière dont le code appelant souhaite utiliser l'API plutôt que de se soucier de l'aspect du code lui-même.
Deuxièmement, cela m'empêche de rédiger une trop grande complexité cyclométique dans une seule méthode, pendant que j'y réfléchis. Chaque chemin supplémentaire à travers une méthode aura tendance à doubler le nombre de tests que je dois faire. La pure paresse dicte qu'après avoir ajouté trop de logique et que je dois écrire 16 tests pour ajouter une condition, il est temps d'en extraire une partie dans une autre méthode / classe et de la tester séparément.
C'est vraiment aussi simple que cela. Ce n'est pas un outil de conception magique.
la source
Ces exigences devraient être reformulées en termes humains. Qui veut savoir quels produits l'utilisateur a déjà visionnés? L'utilisateur? Un vendeur?
Comment? De nom? Par marque? La première étape du développement piloté par les tests consiste à définir un test, par exemple:
>
Si ce sont les seules exigences, je ne ferais certainement pas un saut pour créer un service produit. Je pourrais créer une page Web très simple avec une liste de produits statique. Cela fonctionnerait parfaitement jusqu'à ce que vous obteniez les conditions requises pour ajouter et supprimer des produits. À ce stade, je pourrais décider qu'il est plus simple d'utiliser une base de données relationnelle et un ORM, et de créer une classe Product mappée sur une seule table. Toujours pas de ProductService. Des classes telles que ProductService seront créées quand et si elles sont nécessaires. Plusieurs requêtes Web doivent peut-être exécuter les mêmes requêtes ou mises à jour. Ensuite, la classe ProductService sera créée pour empêcher la duplication de code.
En résumé, TDD pilote le code à écrire. La conception se produit lorsque vous faites des choix d'implémentation, puis refactorisez le code en classes pour éliminer les doublons et contrôler les dépendances. Au fur et à mesure que vous ajoutez du code, vous devrez créer de nouvelles classes pour conserver le code SOLID. Mais vous n'avez pas besoin de décider à l'avance que vous aurez besoin d'une classe de produit et d'une classe de service de produit. Vous trouverez peut-être que la vie est parfaite avec juste une classe de produits.
la source
ProductService
alors. Mais comment TDD vous a-t-il dit qu'il vous fallait une base de données et un ORM?D'autres peuvent ne pas être d'accord, mais pour moi beaucoup de méthodologies plus récentes reposent sur l'hypothèse que le développeur va faire la plupart de ce que les méthodologies plus anciennes décrivaient juste par habitude ou par fierté personnelle, que le développeur fait habituellement quelque chose d'assez évident pour eux, et le travail est encapsulé dans un langage propre ou dans les parties propres d’un langage un peu brouillon afin que vous puissiez effectuer toutes les opérations de test.
Quelques exemples où je suis tombé sur cela dans le passé:
Prenez un groupe d’entrepreneurs spécialisés dans les travaux et leur dites que leur équipe est agile et test d’abord. Ils n'ont souvent pas l'habitude de travailler selon les spécifications et ils ne se soucient pas de la qualité du travail, tant qu'il dure assez longtemps pour que le projet soit terminé.
Essayez de faire quelque chose de nouveau test d'abord, passez une grande partie de votre temps à déchirer les tests lorsque vous trouvez que différentes approches et interfaces sont de la merde.
Codez quelque chose de bas niveau et soyez soit giflé pour le manque de couverture, soit écrivez un grand nombre de tests qui ne représentent pas une grande valeur, car vous ne pouvez pas vous moquer des comportements sous-jacents auxquels vous êtes lié.
Si vous faites du TDD et que cela fonctionne pour votre bien, c'est bon pour vous, mais il y a beaucoup de choses (des tâches entières ou des étapes d'un projet) là où cela n'ajoute tout simplement pas de valeur.
Votre exemple sonne comme si vous n’êtes même pas encore parvenu à une conception. Vous devez donc avoir une conversation sur l’architecture ou créer un prototypage. À mon avis, vous devez d'abord en tenir compte.
la source
Je suis convaincu que TDD constitue une approche très précieuse pour la conception détaillée du système, à savoir les API et le modèle objet. Cependant, pour arriver à un point où vous commenceriez à utiliser TDD, vous devez avoir une vue d'ensemble du projet déjà modélisée d'une manière ou d'une autre et vous devez également avoir une vue d'ensemble de l'architecture telle qu'elle a déjà été modélisée. @ user414076 paraphrase Robert Martin comme ayant une idée de design en tête, sans être marié à celle-ci. Exactement. Conclusion - TDD n’est pas la seule activité de conception en cours, c’est la manière dont les détails de la conception sont précisés. Le TDD doit être précédé par d'autres activités de conception et s'intégrer dans une approche globale (telle que l'agilité) qui traite de la manière dont la conception globale est créée et évolue.
FYI - deux livres que je recommande sur le sujet et qui donnent des exemples concrets et réalistes:
Logiciel croissant orienté objet, guidé par des tests - explique et donne un exemple complet du projet. Ceci est un livre sur le design, pas les tests . Les tests servent à spécifier le comportement attendu lors des activités de conception.
Guide de développement - Guide de développement pratique - une procédure lente et pas à pas permettant de développer une application complète, bien que petite.
la source
TTD entraîne la découverte de la conception par échec de test, et non par succès. Vous pouvez donc tester des inconnus et procéder à un nouveau test répétitif au fur et à mesure que les inconnus sont exposés, ce qui aboutit à un ensemble complet de tests unitaires. Retrofit après l'écriture / libération du code.
Par exemple, vous pouvez être obligé de saisir plusieurs formats différents, mais tous ne sont pas encore connus. En utilisant TDD, vous écrivez d’abord un test qui vérifie que la sortie appropriée est fournie, quel que soit le format d’entrée. Évidemment, ce test échouera. Vous devez donc écrire du code pour gérer les formats connus et effectuer un nouveau test. Comme les formats inconnus sont exposés lors de la collecte des exigences, de nouveaux tests sont écrits avant l' écriture du code, ils devraient également échouer. Ensuite, un nouveau code est écrit pour prendre en charge les nouveaux formats et tous les tests sont réexécutés, ce qui réduit les risques de régression.
Il est également utile de considérer l'échec de l'unité comme un code "non fini" au lieu d'un code "défectueux". TDD autorise les unités inachevées (défaillances attendues), mais réduit le nombre de défaillances d’unités (défaillances inattendues).
la source
Dans la question, il est indiqué:
Ils sont arrivés à cette conclusion en réfléchissant à la façon dont ils allaient tester ce produit. "Quel genre de produit fait ça?" "Eh bien, nous pourrions créer un service". "Ok, écrivons un test pour un tel service"
la source
Une fonctionnalité peut avoir plusieurs conceptions et TDD ne vous dira pas lequel est le meilleur. Même si les tests vous aident à construire un code plus modulaire, cela peut également vous amener à construire des modules qui répondent aux exigences des tests et non à la réalité de la production. Vous devez donc comprendre où vous allez et comment les choses devraient s’intégrer dans l’ensemble. Autrement dit, il existe des exigences fonctionnelles et non fonctionnelles, n'oubliez pas la dernière.
En ce qui concerne la conception, je me réfère aux livres de Robert C. Martin (développement agile), mais aussi aux modèles d'architecture d'application et de conception de domaine de Martin Fowler. Ce dernier point est particulièrement systématique pour extraire les entités et les relations des exigences.
Ensuite, lorsque vous aurez une idée précise des options à votre disposition pour gérer ces entités, vous pourrez alimenter votre approche TDD.
la source
Non.
Comment pouvez-vous tester quelque chose que vous n'avez pas conçu en premier?
Ce ne sont pas des exigences, ce sont des définitions de données. Je ne sais pas en quoi consiste votre logiciel, mais il est peu probable que les analystes parlent de cette façon.
Vous devez savoir quels sont les invariants de votre système.
Une exigence serait quelque chose comme:
Donc, si c'est la seule exigence, vous pouvez avoir une classe comme:
Ensuite, en utilisant TDD, vous écririez un scénario de test avant d'implémenter la méthode order ().
Ainsi, le second test échouera. Vous pourrez alors implémenter la méthode order () comme vous le souhaitez.
la source
Vous avez tout à fait raison, le TDD se traduira par une bonne implémentation d’une conception donnée. Cela n'aidera pas votre processus de conception.
la source
TDD aide beaucoup, cependant il y a une partie importante dans le développement de logiciel. Le développeur doit écouter le code en cours d’écriture. Le refactoring est la 3ème partie du cycle TDD. C’est la principale étape à laquelle les développeurs doivent se concentrer et réfléchir avant de passer au prochain test rouge. Y a-t-il une duplication? Les principes SOLID sont-ils appliqués? Qu'en est-il de la forte cohésion et du faible couplage? Qu'en est-il des noms? Examinez de plus près le code issu des tests et voyez s'il y a quelque chose à modifier, à revoir. Questionnez le code et le code vous dira comment il doit être conçu. J'écris habituellement des ensembles de tests multiples, examine cette liste et crée le premier modèle simple. Il n'est pas nécessaire qu'il soit final, ce n'est généralement pas le cas, car il a changé lors de l'ajout de nouveaux tests. C'est là que le design vient.
la source