web-dev-qa-db-fra.com

Les tests de développement piloté par les tests (TDD) sont-ils toujours des tests unitaires?

Je comprends le développement piloté par les tests jusqu'à présent que vous n'êtes autorisé à écrire du code productif que si vous avez un test unitaire (rouge) qui échoue. Sur cette base, je me demande si l'approche pilotée par les tests peut également être appliquée à d'autres formes de tests.

41
user1364368

Tout ce que TDD vous demande, c'est d'écrire un test qui échoue, puis de modifier votre code pour le faire passer.

En général, les "tests unitaires" sont petits et rapides et testent une partie de votre code de manière isolée. Parce qu'ils sont rapides, cela rend la boucle rouge/verte/refactor aussi rapide. Cependant, ils ne souffrent que de tester les pièces isolément. Vous avez donc également besoin d'autres tests (intégration, acceptation, etc.). Il est toujours recommandé de suivre les mêmes principes: écrire un test qui échoue, puis modifier le code pour le faire fonctionner. Sachez simplement qu'ils sont généralement plus lents, ce qui peut affecter le temps de cycle rouge/vert/refactor.

27
David Arno

Le cycle de refactorisation rouge vert est construit sur un principe très solide:

Seuls les tests de confiance que vous avez vus réussir et échouer.

Oui, cela fonctionne également avec les tests d'intégration automatisés. Également des tests manuels. Heck, il fonctionne sur les testeurs de batterie de voiture. C'est ainsi que vous testez le test.

Certains pensent que les tests unitaires couvrent la plus petite chose qui peut être testée. Certains pensent à tout ce qui est rapide à tester. TDD est plus que le cycle de refactorisation rouge-vert, mais cette partie a un ensemble de tests très spécifique: ce ne sont pas les tests que vous exécuterez idéalement une fois avant de soumettre une collection de modifications. Ce sont les tests que vous exécuterez chaque fois que vous apporterez des modifications. Pour moi, ce sont vos tests unitaires.

59
candied_orange

Cependant, je me demande si l'approche pilotée par les tests peut également être appliquée à d'autres formes de tests.

Oui, et une approche bien connue qui le fait est développement axé sur le comportement . Les tests qui sont générés à partir de la spécification formelle dans BDD pourraient être appelés "tests unitaires", mais ils ne seront généralement pas aussi bas que dans le TDD réel, ils s'adapteront probablement mieux au terme "tests d'acceptation".

12
Doc Brown

Je comprends le développement piloté par les tests jusqu'à présent que vous n'êtes autorisé à écrire du code productif que si vous avez un test unitaire (rouge) qui échoue.

Non. Vous êtes seulement autorisé à écrire le code le plus simple possible pour changer le message du test. Cela ne dit rien sur le type de test.

En fait, vous commencerez probablement par écrire un test d'acceptation (rouge) qui échoue pour un critère d'acceptation, plus précisément, vous écrivez le test d'acceptation le plus simple qui pourrait éventuellement échouer; ensuite, vous exécutez le test, le regardez échouer et vérifiez qu'il échoue pour la bonne raison. Ensuite, vous écrivez un test fonctionnel qui échoue pour une tranche de fonctionnalité de ce critère d'acceptation, encore une fois, vous écrivez le test fonctionnel le plus simple qui pourrait éventuellement échouer, l'exécutez, le regardez échouer et vérifiez qu'il échoue pour la bonne raison. Ensuite, vous écrivez un test unitaire qui échoue, le test unitaire le plus simple qui pourrait éventuellement échouer, l'exécutez, regardez-le échouer, vérifiez qu'il échoue pour la bonne raison.

Maintenant, vous écrivez le code de production le plus simple qui pourrait éventuellement changer le message d'erreur. Exécutez à nouveau le test, vérifiez que le message d'erreur a changé, qu'il a changé dans la bonne direction et que le code a modifié le message pour la bonne raison. (Idéalement, le message d'erreur devrait disparaître maintenant et le test devrait réussir, mais le plus souvent, il est préférable de prendre de petites étapes pour changer le message au lieu d'essayer de réussir le test en une seule fois - c'est la raison pourquoi les développeurs de frameworks de test consacrent autant d'efforts à leurs messages d'erreur!)

Une fois le test unitaire réussi, vous refactorisez votre code de production sous la protection de vos tests. (Notez qu'à l'heure actuelle, le test d'acceptation et le test fonctionnel échouent toujours, mais ce n'est pas grave, car vous ne refactorisez que les unités individuelles couvertes par les tests unitaires.)

Maintenant, vous créez le test unitaire suivant et répétez ce qui précède, jusqu'à ce que le test fonctionnel réussisse également. Sous la protection du test fonctionnel, vous pouvez désormais effectuer des refactorings sur plusieurs unités.

Ce cycle intermédiaire se répète maintenant jusqu'à la réussite du test d'acceptation, auquel cas vous pouvez désormais effectuer des refactorisations sur l'ensemble du système.

Maintenant, vous choisissez le critère d'acceptation suivant et le cycle extérieur recommence.

Kent Beck, le "découvreur" de TDD (il n'aime pas le terme "inventeur", il dit que les gens l'ont fait depuis le début, il lui a juste donné un nom et a écrit un livre à ce sujet) utilise une analogie de la photographie et appelle cela "zoom avant et arrière".

Remarque: vous n'avez pas toujours besoin de trois niveaux de tests. Peut-être, parfois, vous en avez besoin de plus. Plus souvent, vous en avez besoin de moins. Si vos fonctionnalités sont petites et que vos tests fonctionnels sont rapides, vous pouvez vous en passer sans (ou avec moins de tests unitaires). Souvent, vous n'avez besoin que de tests d'acceptation et de tests unitaires. Ou, vos critères d'acceptation sont si fins que vos tests d'acceptation le sont tests fonctionnels.

Kent Beck dit que s'il a un test fonctionnel rapide, petit et ciblé, il va d'abord écrire les tests unitaires, laisser les tests unitaires piloter le code, puis supprimer à nouveau (certains) les tests unitaires qui couvrent le code qui est également couvert par le test fonctionnel rapide. N'oubliez pas: le code de test est aussi du code qui doit être maintenu et refactorisé, moins il y en a, mieux c'est!

Cependant, je me demande si l'approche pilotée par les tests peut également être appliquée à d'autres formes de tests.

Vous n'appliquez pas vraiment TDD aux tests. Vous l'appliquez à l'ensemble de votre processus de développement. C'est ce que la partie "pilotée" de Test - Pilotée - Développement signifie: tout votre développement est piloté par des tests. Les tests ne pilotent pas seulement le code que vous écrivez, ils conduisent également quoi le code à écrire, le code à écrire ensuite. Ils guident votre conception. Ils vous disent quand vous avez terminé. Ils vous disent sur quoi travailler ensuite. Ils vous renseignent sur les défauts de conception de votre code (lorsque les tests sont difficiles à écrire).

Keith Braithwaite a créé un exercice qu'il appelle TDD comme si vous le vouliez . Il consiste en un ensemble de règles (basées sur Les Trois Règles de l'Oncle Bob Martin sur TDD , mais beaucoup plus strictes) que vous devez suivre strictement et qui sont conçues pour vous orienter vers l'application de TDD plus rigoureusement. Cela fonctionne mieux avec la programmation en binôme (afin que votre binôme s'assure que vous n'enfreignez pas les règles) et avec un instructeur.

Les règles sont les suivantes:

  1. Écrivez exactement un nouveau test, le plus petit test possible qui semble pointer dans la direction d'une solution
  2. Voyez-le échouer; les échecs de compilation comptent comme des échecs
  3. Faites passer le test à partir de (1) en écrivant le moins de code d'implémentation possible dans la méthode de test.
  4. Refactoriser pour supprimer la duplication et, au besoin, pour améliorer la conception. Soyez strict quant à l'utilisation de ces mouvements:
    1. vous voulez une nouvelle méthode - attendez le temps de refactoring, puis ... créez de nouvelles méthodes (non-test) en faisant l'une de celles-ci, et en aucune autre manière :
      • préféré: faire Extraire la méthode sur le code d'implémentation créé selon (3) pour créer une nouvelle méthode dans la classe de test, ou
      • si vous devez: déplacer le code d'implémentation selon (3) dans une méthode d'implémentation existante
    2. vous voulez une nouvelle classe - attendez le temps de refactoring, puis ... créez des classes non-test pour fournir une destination pour une méthode Move et pour aucune autre raison
    3. remplir les classes d'implémentation avec des méthodes en faisant la méthode Move, et pas d'autre moyen

Ces règles sont destinées à l'exercice du TDD. Ils ne sont pas destinés à faire du TDD en production (bien que rien ne vous empêche de l'essayer). Ils peuvent se sentir frustrés car il semblera parfois que vous fassiez des milliers de minuscules petits pas sans faire de réels progrès.

8
Jörg W Mittag

TDD ne se limite pas du tout à ce que la communauté traditionnelle des tests de logiciels appelle les "tests unitaires". Ce malentendu très courant est le résultat de la surcharge malheureuse de Kent Beck du terme "unité" lorsqu'il décrit sa pratique du TDD. Ce qu'il entendait par "test unitaire" était un test qui se déroulait isolément. Il ne dépend pas d'autres tests. Chaque test doit configurer l'état dont il a besoin et effectuer tout nettoyage lorsqu'il est terminé. C'est en ce sens qu'un test unitaire au sens TDD est une unité. Il est autonome. Il peut s'exécuter seul ou avec n'importe quel autre test unitaire dans n'importe quel ordre.

Référence: "Test Driven Development By Example", par Kent Beck

Kent Beck décrit ce qu'il entend par "test unitaire" au chapitre 32 - Maîtriser le TDD

2
Jason Desrosiers

Je n'ai pas lu de livres à ce sujet, et je ne suis pas tout à fait en train de suivre les pratiques TDD "standard" tout le temps, mais dans mon esprit, le point principal de la philosophie TDD, avec lequel je suis entièrement d'accord, est que vous devez d'abord définir le succès . Ceci est important à tous les niveaux de la conception, de "Quel est le but de ce projet?" à "Quelles devraient être les entrées et les sorties de cette petite méthode?"

Il existe de nombreuses façons de faire cette définition du succès. Une méthode utile, en particulier pour les méthodes de bas niveau avec potentiellement de nombreux cas Edge, consiste à écrire des tests dans du code. Pour certains niveaux d'abstraction, il peut être utile de simplement écrire une note rapide sur l'objectif du module ou autre chose, ou même simplement de vous vérifier mentalement (ou de demander à un collègue) pour vous assurer que tout a du sens et est dans un lieu logique. Parfois, il est utile de décrire un test d'intégration dans le code (et bien sûr, cela aide à l'automatiser), et parfois il est utile de simplement définir un plan de test rapide raisonnable que vous pouvez utiliser pour vous assurer que tous les systèmes fonctionnent ensemble de la manière dont vous attendent.

Mais quelles que soient les techniques ou les outils spécifiques que vous utilisez, dans mon esprit, l'élément clé à retirer de la philosophie TDD est que la définition du succès passe d'abord. Sinon, vous lancez la fléchette puis peignez la bulle autour de l'endroit où il est arrivé.

1
user101289

Dans le discours Développement piloté par les tests: ce n'est pas ce que nous voulions dire Steve Freeman montre la diapositive suivante de la grande image de TDD (voir l'image ci-dessous la réponse). Cela comprend une étape "Ecrire un test de bout en bout" qui est suivie par "Ecrire un test unitaire ayant échoué". (Cliquez pour agrandir, c'est en haut à droite)

Donc non dans TDD les tests ne sont pas toujours des tests unitaires.

Et oui, vous pouvez (et devriez peut-être) commencer par un test de bout en bout de niveau supérieur qui échoue avant de vous écrire votre premier test unitaire. Ce test décrit le comportement que vous souhaitez obtenir. Cela génère une couverture à plus de niveaux de la test-pyramid . Adrian Sutton explique l'expérience de LMAX qui montre que les tests de bout en bout peuvent jouer un rôle important et précieux .

enter image description here

1