Quel est le meilleur plan d'action dans TDD si, après avoir mis en œuvre la logique correctement, le test échoue toujours (car il y a une erreur dans le test)?
Par exemple, supposons que vous souhaitiez développer la fonction suivante:
int add(int a, int b) {
return a + b;
}
Supposons que nous le développions dans les étapes suivantes:
Ecrire un test (pas encore de fonction):
// test1
Assert.assertEquals(5, add(2, 3));
Entraîne une erreur de compilation.
Écrivez une mise en oeuvre de la fonction factice:
int add(int a, int b) {
return 5;
}
Résultat: test1
passe.
Ajouter un autre cas de test:
// test2 -- notice the wrong expected value (should be 11)!
Assert.assertEquals(12, add(5, 6));
Résultat: test2
échoue, test1
passe toujours.
Écrire une réelle implémentation:
int add(int a, int b) {
return a + b;
}
Résultat: test1
passe toujours, test2
échoue toujours (depuis 11 != 12
).
Dans ce cas particulier: serait-il préférable de:
test2
, et voir qu'il passe maintenant, outest2
et laissez-le échouer, puis réintroduire la bonne implémentation (étape n ° 4 ci-dessus).Ou y a-t-il une autre façon intelligente?
Bien que je comprenne que l'exemple de problème est plutôt trivial, je suis intéressé par ce qu'il faut faire dans le cas générique, qui pourrait être plus complexe que l'ajout de deux nombres.
ÉDITER (En réponse à la réponse de @THOMAS Junk):
La TDD suggère dans une telle affaire, pas ce qui est "la meilleure pratique universelle" pour la réalisation de bon code ou de tests (ce qui pourrait être différent de la TDD-Way).
La chose absolument critique est que vous voyez le test à la fois passe et échouez.
Que vous supprimiez le code pour effectuer l'échec du test, réécrivez le code ou éteignez-le dans le Presse-papiers uniquement pour le coller plus tard n'a pas d'importance. TDD n'a jamais dit que vous deviez retaper quoi que ce soit. Il veut savoir que le test ne passe que lorsque cela devrait passer et échouer uniquement lorsqu'il devrait échouer.
Voir le test à la fois passe et échouer est la façon dont vous testez le test. Ne faites jamais confiance à un test que vous n'avez jamais vu faire les deux.
refactoring contre la barre rouge nous donne des étapes formelles pour refactoriser un test de travail:
Cependant, nous ne refactons pas un test de travail. Nous devons transformer un test de buggy. Une préoccupation est le code qui a été introduit, alors que seul ce test le recouvert. Ce code doit être renvoyé et réintroduit une fois que le test est fixé.
Si ce n'est pas le cas et que la couverture du code n'est pas une préoccupation due à d'autres tests couvrant le code, vous pouvez transformer le test et l'introduire comme un test vert.
Ici, le code est également en cours de roulé mais juste assez pour que le test échoue. Si cela ne suffit pas pour couvrir tout le code introduit uniquement dans le cadre du test de buggy, nous avons besoin d'un nouveau retour de code et d'autres tests.
Introduire un test vert
Briser le code peut être commenter le code ou le déplacer ailleurs seulement pour le coller plus tard. Cela nous montre la portée du code des couvercles de test.
Pour ces deux dernières exécutions, vous revenez de retour dans le cycle vert rouge normal. Vous ne faites que coller au lieu de taper pour désabaisser le code et faire passer le test. Alors assurez-vous que vous ne collez assez que suffisamment pour faire passer le test.
Le motif global ici est de voir la couleur du test change comme nous nous attendons. Notez que cela crée une situation où vous avez brièvement un test vert de confiance. Soyez prudent de se faire interrompre et d'oublier où vous êtes en ces étapes.
Mes remerciements à RubberDuck pour le embrasser la barre rouge Link.
Dans ce cas particulier, si vous changez de 12 à un 11 et que le test passe maintenant, je pense que vous avez fait du bon travail de tester le test ainsi que la mise en œuvre, il n'est donc pas nécessaire de passer à travers des cerceaux supplémentaires.
Cependant, le même problème peut se présenter dans des situations plus complexes, telles que lorsque vous avez une erreur dans votre code de configuration. Dans ce cas, après avoir corrigé votre test, vous devriez probablement essayer de muter votre implémentation de manière à obtenir ce test particulier pour échouer, puis revenir à la mutation. Si vous revenez la mise en œuvre est le moyen le plus simple de le faire, alors c'est bien. Dans votre exemple, vous pourriez muté a + b
à a + a
ou a * b
.
Sinon, si vous pouvez légèrement muter l'affirmation et voir l'échec du test, cela peut être assez efficace pour tester le test.
Je dirais que ceci est un cas pour votre système de contrôle de version préféré:
Étape la correction du test, conservant vos modifications de code dans votre répertoire de travail.
[.____] commit avec un message correspondant Fixed test ... to expect correct output
.
Avec git
, cela peut nécessiter une utilisation de git add -p
Si le test et la mise en œuvre sont dans le même fichier, sinon vous ne pouvez évidemment pas stabiliser les deux fichiers séparément.
Commettre le code de la mise en œuvre.
Retournez à temps pour tester la commission commise à l'étape 1, en veillant à ce que le test échoue en réalité.
Vous voyez, de cette façon, vous ne vous appuyez pas sur vos prouesses de montage pour déplacer votre code de mise en œuvre hors de la manière dont vous testez votre test de défaillance. Vous utilisez votre VCS pour enregistrer votre travail et vous assurer que l'historique enregistré par la VCS inclut correctement l'échec et le test de passage.