Le cycle rouge - vert - refacteur pour TDD est bien établi et accepté. Nous écrivons n Test de l'unité à défaut et le faire passer aussi simplement que possible. Quels sont les avantages à cette approche sur l'écriture plusieurs Échec des tests unitaires pour une classe et les faire passer en une fois.
La suite de test vous protège toujours contre l'écriture de code incorrect ou en faisant des erreurs dans la phase de refactoring, alors quel est le mal? Parfois, il est plus facile d'écrire tous les tests d'une classe (ou d'un module) d'abord sous la forme d'une forme de "décharge de cerveau" pour écrire rapidement tout le comportement attendu en une fois.
Lorsque vous écrivez n test, vous vous concentrez sur n chose.
[.____] Avec de nombreux tests, vous avez attiré votre attention sur de nombreuses tâches, ce n'est donc pas une bonne idée.
L'une des difficultés lors de l'écriture des tests unitaires est que vous écrivez du code, et que lui-même peut potentiellement être sujettes à l'erreur. Il y a aussi la possibilité que vous pourriez finir par avoir besoin de changer vos tests plus tard à la suite d'un effort de refactoring que vous écrivez votre code de mise en œuvre. Avec TDD, cela signifie que vous pourriez finir par obtenir potentiellement un peu trop emporté avec vos tests et trouver votre auto avoir besoin de réécrire beaucoup de code de test essentiellement " non testé " comme vient à échéance de mise en œuvre au cours du projet. Une façon d'éviter ce genre de problème est de se concentrer simplement sur une chose unique à la fois. Cela vous permet de minimiser l'impact de tout changement sur vos tests.
Bien sûr, cela vient en grande partie à la façon dont vous écrivez votre code de test. Écrivez-vous un test unitaire pour chaque méthode individuelle, ou êtes-vous en train d'écrire des tests qui mettent l'accent sur les caractéristiques/besoins/comportements? Une autre approche pourrait être d'utiliser une approche du comportement Driven avec un cadre approprié, et se concentrer sur l'écriture de tests comme si elles sont des spécifications. Cela signifierait soit l'adoption de la méthode BDD, ou d'adapter les tests BDD si vous souhaitez coller avec TDD plus formelle. Sinon, vous pourriez tenir tout à fait avec le paradigme de TDD, mais modifier la façon dont vous écrivez des tests de sorte qu'au lieu de se concentrer entièrement sur les méthodes d'essai individuellement, vous tester des comportements plus généralement comme un moyen pour répondre aux spécificités des besoins fonctionnalités que vous utiliserez.
Quelle que soit l'approche spécifique que vous prenez, dans tous les cas que je viens de décrire ci-dessus vous utilisez une approche de test en premier lieu, si bien qu'il peut être tentant de simplement télécharger votre cerveau dans une suite de tests belle, vous voulez aussi lutter contre la la tentation de faire plus que ce qui est absolument nécessaire. Chaque fois que je suis sur le point de commencer une nouvelle suite de test je commence à répéter YAGNI à moi-même, et parfois même le jeter dans un commentaire dans mon code pour me rappeler de rester concentré sur ce qui est important dans l'immédiat, et de ne faire que le minimum requis pour satisfaire la les exigences de la fonction, je suis sur le point de mettre en œuvre. Tenir à Red-Green-Refactor aide à vous assurer que vous le ferez.
Je pense en faisant cela, vous manquez sur le processus de TDD. En écrivant simplement tous vos tests au début, vous ne suivez pas vraiment le processus de développement de TDD. Vous devinez simplement les tests dont vous aurez besoin. Ce sera un ensemble de tests très différents de ceux que vous finissez par écrire si vous les faites une à la fois pendant que vous développez votre code. (À moins que votre programme ne soit pas trivial de nature.)
L'idée derrière TDD est une itérations rapides.
Si vous avez des bandes de tests importants qui doivent être écrits avant de devoir écrire votre code, il est difficile de refroidir de manière itérale votre code.
Sans le refactoring Code facile Vous perdez beaucoup d'avantages de TDD.
Je fais "écrire" tous les tests que je peux penser à l'avant, tandis que "Cerveau d'assaut", mais j'écris chaque test en une seule Commentaire décrivant le test.
Je convertis ensuite un test en code et faire le travail afin de pouvoir compiler et passer. Souvent, je décide que je n'ai pas besoin de tous les tests que je pensais que je pensais, ou j'ai besoin de tests différents, ces informations ne proviennent que de l'écriture du code pour faire passer les tests.
Le problème est que vous ne pouvez pas écrire un test en code tant que vous n'avez pas créé la méthode et les classes qu'il teste, sinon vous obtiendrez de nombreuses erreurs de compilateur qui vous permettent de travailler sur un seul test à la fois.
Maintenant, si vous utilisez un système tel que Spec Flow lorsque les tests sont écrits dans "Anglais", vous souhaiterez peut-être que les clients acceptent d'accepter un ensemble de tests pendant que vous avez leur temps, plutôt que de créer un seul test.
Dans mon expérience (limitée) avec TDD, je peux vous dire que chaque Durée, j'ai cassé la discipline d'écrire un test à la fois, les choses ont mal passé. C'est un piège facile à tomber dans. "Oh, cette méthode est triviale", vous pensez à vous-même ", je vais donc éliminer ces deux autres tests connexes et continuer à bouger." Bien devinez quoi? Rien n'est aussi trivial que cela semble. Chaque fois que je suis tombé dans ce piège, j'ai fini par déboguer quelque chose que je pensait était facile, mais s'est avéré avoir des cas d'angle bizarre. Et comme j'avais fini d'écrire plusieurs tests à la fois, c'était beaucoup de travail à suivre où se trouvait le bug.
Si vous avez besoin d'une dump d'information sur le cerveau, vous avez beaucoup d'options:
Notez que Nulle part sur cette liste est le compilateur. :-)
Vous supposez que vous sachiez ce que votre code ressemblera avant de l'écrire. TDD/BDD est autant un processus de conception/découverte qu'il s'agit d'un processus QA. Pour une fonctionnalité donnée, vous écrivez le test le plus simple qui vérifierait que la fonctionnalité est satisfaite (cela peut parfois nécessiter plusieurs en raison de la complexité d'une caractéristique). Ce premier test que vous écrivez est chargé d'hypothèses de ce que le code de travail ressemblera. Si vous écrivez la suite de tests entière avant d'écrire la première ligne de code pour l'appuyer, vous faites une litanie d'hypothèses non vérifiées. Au lieu de cela, écrivez une hypothèse et vérifiez-la. Puis écrivez le prochain. Dans le processus de vérification de la prochaine hypothèse, vous risquez de casser une hypothèse antérieure pour que vous puissiez revenir en arrière et changer de première hypothèse pour faire correspondre la réalité ou changer la réalité afin que la première hypothèse s'applique toujours.
Pensez à chaque test de l'unité que vous écrivez comme une théorie dans un ordinateur portable scientifique. Lorsque vous remplissez le cahier, vous prouvez vos théories et formez de nouveaux. Parfois, prouvant une nouvelle théorie déprempote une théorie précédente, vous devez donc le réparer. Il est plus facile de prouver une théorie à la fois plutôt que d'essayer de prouver 20 à la fois.
Au-delà de la pensée juste d'une chose, un paradigme de TDD est d'écrire le code moins possible de passer le test. Lorsque vous écrivez un test à la fois, il est beaucoup plus facile de voir le chemin de l'écriture de code juste assez pour obtenir ce test à passer. Avec une suite complète de tests pour passer, vous ne venez pas le code en petites étapes, mais doivent faire un grand saut pour les faire tous passer en une seule fois.
Maintenant, si vous ne vous limitez pas à écrire le code pour les faire tous passer " en une seule fois ", mais plutôt d'écrire du code juste assez pour passer un test à la fois, il pourrait encore travailler. Il faudrait avoir plus de discipline pour ne pas simplement aller de l'avant et d'écrire plus de code que vous avez besoin, cependant. Une fois que vous commencez dans cette voie, vous vous laisser ouvert à écrire plus de code que les tests décrivent, qui peut être non testé, au moins dans le sens où il n'est pas conduit par un test et peut-être dans le sens qu'il est pas nécessaire (ou exercé) par un test.
Se mettre ce que la méthode devrait faire, comme des commentaires, des histoires, une spécification fonctionnelle, etc., est tout à fait acceptable. Je hâte de les traduire en essais un à la fois cependant.
L'autre chose que vous pouvez manquer en écrivant les essais est à la fois le processus de réflexion qui passe un test peut vous demander de penser à d'autres cas de test. Sans une banque de tests existants, vous devez penser à l'autre cas de test dans le cadre du dernier test de passage. Comme je l'ai dit, d'avoir une bonne idée de ce que la méthode est censée faire est très bon, mais beaucoup de fois où je me suis trouvé de trouver de nouvelles possibilités que je ne l'avais pas considéré a priori, mais qui ne se produisait dans le processus d'écriture du des tests. Il y a un danger que vous pourriez manquer ces sauf si vous obtenez spécifiquement l'habitude de penser ce que les nouveaux tests de puis-je écrire que je ne possède pas déjà.
J'ai travaillé sur un projet où les développeurs qui ont écrit les tests (défaillants) étaient différents des développeurs mettant en œuvre le code nécessaire pour les faire passer et je l'ai trouvé vraiment efficace.
Dans ce cas, seuls les tests liés à l'itération actuelle ont été écrits une fois. Donc, ce que vous suggérez est parfaitement possible dans ce type de scénario.
Le cycle rouge-vert-refacteur est une liste de contrôle destinée aux développeurs Nouveau à TDD. Je dirais que c'est une bonne idée de suivre cette liste de contrôle jusqu'à ce que vous sachiez quand vous le suivez et lorsque vous pouvez le casser (c'est-à-dire jusqu'à ce que je sache, n'êtes pas obligé de poser cette question sur Stackoverflow :)
Avoir fait TDD pour près d'une décennie, je peux vous dire que je suis très rarement, si jamais, écrivez de nombreux tests échoués avant d'écrire un code de production.
Un test à l'heure: le principal avantage est la concentration sur une chose. Pensez à la première conception de profondeur: vous pouvez aller en profondeur et rester concentré avec une boucle de retour rapide. Vous risquez de manquer la portée de tout le problème! C'est le moment (grand) refactoring entre en jeu. Sans cela, TDD ne fonctionne pas.
Tous les tests: L'analyse et la conception peuvent vous révéler davantage de la portée du problème. Pensez à un premier design de la largeur. Vous analysez le problème de plus d'angles et ajoutez des informations de l'expérience. C'est intrinsèquement plus difficile, mais peut générer des avantages intéressants - moins de refactoring - si vous faites suffisamment ". Méfiez-vous qu'il est facile de sur-analyser et encore complètement la marque!
J'ai du mal à recommander généralement de préférer préférer l'un ou l'autre, car les facteurs sont nombreux: l'expérience (en particulier avec le même problème), les connaissances et les compétences de domaine, la convivialité du code de refactoring, la complexité du problème ...
Je suppose que si nous nous concentrons plus étroitement sur des applications métiers typiques, alors TDD avec son approche de première épreuve et d'erreur rapide gagnerait généralement en termes d'efficacité.
Vous décrivez BDD, lorsque certains parties prenantes externes ont une spécification exécutable. Cela peut être bénéfique s'il y a une spécification avant prédéterminée (par exemple, une spécification de format, une norme industrielle ou si le programmeur n'est pas l'expert de domaine).
L'approche normale consiste alors à couvrir progressivement de plus en plus de tests d'acceptation, ce qui est la progression visible par rapport au chef de projet et au client.
Vous avez généralement ces tests spécifiés et exécutés dans un cadre BDD tel que concombre, Fitessse ou d'autres.
Cependant, ce n'est pas quelque chose que vous mélangez avec vos tests unitaires, qui sont beaucoup plus proches des détails de la mise en œuvre de Nitty Gritty avec de nombreux étuis de bord liés à l'API, des problèmes d'initialisation, etc. fortement concentrés sur l'élément Sous test , qui est un mise en œuvre artefact.
La discipline de refacteur rouge-vert a beaucoup d'avantages et le seul avantage que vous puissiez espérer en les tapant à l'avant, c'est de se casser même.
En supposant que votre structure de test le supporte, ce que je suggérerais, c'est que, au lieu de mise en œuvre Les tests que vous souhaitez braindump, écrivez plutôt des tests en attente descriptifs que vous effectuerez ultérieurement. Par exemple, si votre API devrait faire FOO et BAR, mais pas BIZ, il suffit d'ajouter le code suivant (cet exemple est dans RSPEC) pour votre suite de test, puis attaquez-les un par un. Vous obtenez vos pensées rapidement et pouvez répondre à tous vos problèmes un par un. Lorsque tous les tests passent, vous saurez quand vous avez adressé toutes vos problèmes que vous avez eu lors de votre cerveau.
describe "Your API" do
it "should foo" do
pending "braindump from 4/2"
end
it "should bar" do
pending "braindump from 4/2"
end
it "should not biz" do
pending "braindump from 4/2"
end
end