Aujourd’hui, nous formions le TDD et avons constaté le malentendu suivant.
La tâche consiste pour l'entrée "1,2" à renvoyer la somme de nombres qui est 3. Ce que j'ai écrit (en C #) était:
numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]); //task said we have two numbers and input is correct
Mais d'autres gars ont préféré le faire autrement. Tout d'abord, pour l'entrée "1,2", ils ont ajouté le code suivant:
if (input == "1,2")
return 3;
Ils ont ensuite introduit un test supplémentaire pour l'entrée "4,5" et ont modifié la mise en oeuvre:
if (input == "1,2")
return 3;
else if (input == "4,5")
return 9;
Et après cela, ils ont dit "D'accord, maintenant nous voyons le schéma" et ont mis en œuvre ce que j'avais initialement fait.
Je pense que la seconde approche correspond mieux à la définition de TDD mais ... devrions-nous être si strict à ce sujet? Pour moi, il est normal de sauter des pas de bébé triviaux et de les combiner en "jumelages" si je suis suffisamment sûr pour ne rien rater. Ai-je tort?
Mise à jour. J'ai commis une erreur en ne clarifiant pas que ce n'était pas le premier test. Il y avait déjà quelques tests, donc "return 3" n'était en réalité pas le code le plus simple pour satisfaire à l'exigence.
Réponses:
Écrivez le code le plus simple qui fait passer les tests.
Pour autant que je sache, aucun de vous ne l'a fait.
Étape bébé 1.
Test: pour l’entrée "1,2", retourne la somme des nombres qui est 3
Faire échouer le test:
Faites passer le test:
Étape bébé 2.
Test: pour l’entrée "1,2", renvoyer la somme des nombres, qui est 3
Test: pour l’entrée "4,5", renvoyer la somme des nombres, qui est 9
Le deuxième test échoue, alors faites le passer:
(Bien plus simple qu'une liste de if ... return)
Vous pouvez certainement faire valoir une mise en œuvre évidente dans ce cas, mais si vous parlez de le faire strictement par petites étapes, il s’agit des étapes correctes, IMO.
L'argument est que si vous n'écrivez pas le deuxième test, une étincelle brillante pourrait apparaître plus tard et "refactoriser" votre code pour qu'il se lise:
Et, sans prendre les deux mesures, vous n’avez jamais fait passer le deuxième test au rouge (ce qui signifie que le test lui-même est suspect).
la source
input.Length
N'est-ce pas exagéré, surtout si l'entrée de la méthode s'avère être une mesure d'un fichier quelque part et que vous avez imprudemment appelé votre méthodeSize()
.Je pense que la deuxième façon est stupide. Je vois l’intérêt de faire des pas assez petits, mais écrire ces petits pas en zygote (je ne peux même pas les appeler bébé) n’est qu’une perte de temps. Surtout si le problème initial que vous résolvez est déjà très petit.
Je sais que c'est de la formation et qu'il s'agit davantage de montrer le principe, mais je pense que de tels exemples font plus que mal le TDD. Si vous voulez montrer la valeur des petits pas, utilisez au moins un problème comportant une certaine valeur.
la source
Kent Beck en parle dans son livre Test Driven Development: By Example.
Votre exemple indique une " implémentation évidente " - vous souhaitez renvoyer la somme de deux valeurs d'entrée, ce qui est un algorithme relativement basique à réaliser. Votre contre-exemple tombe dans "simulez jusqu'à ce que vous le fabriquiez" (bien que ce soit un cas très simple).
Une implémentation évidente peut être beaucoup plus compliquée que cela - mais elle fonctionne lorsque la spécification d'une méthode est assez stricte - par exemple, renvoyer une version codée en URL d'une propriété de classe - vous n'avez pas besoin de perdre du temps avec beaucoup faux encodages.
Une routine de connexion à une base de données, en revanche, nécessiterait un peu plus de réflexion et de test afin d'éviter toute implémentation évidente (même si vous en avez peut-être déjà écrit plusieurs fois sur d'autres projets).
Du livre:
la source
Je vois cela comme suit la lettre de la loi, mais pas son esprit.
Vos pas de bébé devraient être:
En outre, le verbe dans la méthode est
sum
Ce n'est pas une somme, c'est un test pour des entrées spécifiques.
la source
Pour moi, il me semble bien de combiner plusieurs étapes de mise en œuvre triviales en une étape légèrement moins triviale - je le fais tout le temps aussi. Je ne pense pas qu'il faille être religieux pour suivre TDD chaque fois à la lettre.
OTOH cela ne s'applique que pour des étapes vraiment triviales comme l'exemple ci-dessus. Pour quelque chose de plus complexe, que je ne peux pas garder complètement dans mon esprit à la fois et / ou où je ne suis pas sûr à 110% du résultat, je préfère aller un pas à la fois.
la source
Comme le montre cette question, la taille des étapes peut être source de confusion. Une question que je me suis souvent posée lorsque j'ai commencé à écrire des applications pilotées par des tests était: Le test que j'écris contribue-t-il au développement de mes applications? Cela peut sembler trivial et sans rapport avec certains, mais accrochez-vous un instant avec moi.
Maintenant, quand je commence à écrire une application, je commence généralement par un test. Ce test est en grande partie lié à ma compréhension de ce que j'essaie de faire. Si je pense avoir le comportement d'un cours dans ma tête, le pas sera grand. Si le problème que j'essaie de résoudre est beaucoup moins clair, alors l'étape peut être simplement que je sais qu'une méthode appelée X est renvoyée et qu'elle renverra Y. À ce stade, la méthode n'aura même aucun paramètre et il est possible que le nom de la méthode et le type de retour changent. Dans les deux cas, les tests pilotent mon développement. Ils me disent des choses sur mon application:
Ce cours que j'ai dans la tête va-t-il réellement fonctionner?
ou
Comment vais-je pouvoir faire ce truc?
Le fait est que je peux basculer entre de grandes et de petites étapes en un clin d'œil. Par exemple, si un grand pas ne fonctionne pas et que je ne vois pas de solution évidente, je passerai à un plus petit pas. Si cela ne fonctionne pas, je vais passer à une étape encore plus petite. Ensuite, il existe d'autres techniques telles que la triangulation si je suis vraiment bloqué.
Si, comme moi, vous êtes un développeur et non un testeur, le but de TDD n'est pas d'écrire des tests, mais d'écrire du code. Ne vous attardez pas pour écrire plein de petits tests s’ils ne vous procurent aucun avantage.
J'espère que votre entrainement avec TDD vous a plu. IMHO si plus de personnes étaient testées infectées, le monde serait un meilleur endroit :)
la source
Dans une introduction aux tests unitaires, j'ai lu la même approche (des étapes qui ont vraiment l'air minuscule), et en réponse à la question "à quel point devraient-elles être minuscules" quelque chose que j'ai aimé, qui était (paraphrasé) comme ceci:
C'est à peu près à quel point vous êtes sûr que les étapes fonctionnent. Vous pouvez faire de grands pas si vous voulez. Mais essayez-le simplement pendant un certain temps et vous découvrirez une confiance peu judicieuse dans les endroits où vous le prenez pour acquis. Ainsi, les tests vous aident à établir une confiance factuelle.
Alors, peut-être que votre collègue est un peu timide :)
la source
N’est-ce pas que la mise en œuvre de la méthode n’est pas pertinente tant que les tests aboutissent? L'extension des tests échouera plus rapidement dans le deuxième exemple, mais peut échouer dans les deux cas.
la source
Je suis d'accord avec les gens qui disent que ni la mise en œuvre la plus simple.
La méthodologie est si stricte qu'elle oblige à rédiger le plus de tests pertinents possible. Renvoyer une valeur constante pour un cas de test et l'appeler passe est acceptable, car cela vous oblige à revenir en arrière et à spécifier ce que vous voulez vraiment pour obtenir autre chose que des bêtises de votre programme. Utiliser un cas aussi trivial, c'est se tirer une balle dans le pied à certains égards, mais le principe est que des erreurs se glissent dans les lacunes de votre spécification lorsque vous essayez de «faire trop» et que vous réduisez l'exigence à la mise en œuvre la plus simple possible Le test doit être écrit pour chaque aspect unique du comportement que vous souhaitez réellement.
la source