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

41

Je comprends jusqu’à présent le développement piloté par les tests: vous n’êtes autorisé à écrire du code productif que si vous avez un test unitaire en échec (rouge). Sur cette base, j'ai la question de savoir si l'approche fondée sur les tests peut également être appliquée à d'autres formes de tests.

utilisateur1364368
la source
6
Il n'est pas rare d'utiliser plus d'un niveau différent de rouge / vert / refactor imbriqués l'un dans l'autre. Par exemple, vous pouvez suivre red / green / refactor lors de la rédaction de tests d'acceptation / de comportement, où la phase «verte» du test d'acceptation contient elle-même plusieurs itérations rouge / vert / refactor des tests unitaires.
Sean Burton
1
Le titre ne correspond pas au contenu de la question. Titre "les tests sont toujours des tests unitaires " (réponse: non, il peut exister d'autres types de tests que les tests unitaires), le contenu demande "devez-vous d'abord écrire le test?".
AnoE
@AnoE La première phrase du contenu est juste une déclaration d'introduction. La phrase en secondes ne demande pas si le test doit être écrit en premier, mais si l'approche TDD peut être utilisée pour des méthodes de test autres que TDD.
user1364368
@ user1364368, n'hésitez pas à reformuler un peu la question. Au moins, j'étais confus quant à votre intention en première lecture, et la question à vote majoritaire, tout en adressant vos deux phrases, commence bien en évidence avec la première.
AnoE
@AnoE J'ai changé le début de la deuxième phrase pour préciser la question.
user1364368

Réponses:

27

Tout ce que TDD exige de vous, c’est que vous écriviez un test qui échoue, puis modifiez votre code pour le faire passer.

Typiquement, les "tests unitaires" sont petits et rapides et testent une partie de votre code de manière isolée. Comme ils sont rapides, la boucle rouge / vert / refactor est également rapide. Cependant, ils ne testent que des pièces isolées. Vous avez donc également besoin d'autres tests (intégration, acceptation, etc.). Il est toujours bon de suivre les mêmes principes: écrivez un test qui échoue, puis modifiez le code pour le faire fonctionner. Sachez simplement qu’ils sont généralement plus lents et peuvent donc affecter le temps de cycle rouge / vert / refactorisation.

David Arno
la source
59

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

Ne faites confiance qu'aux tests que vous avez vus réussir et échouer.

Oui, cela fonctionne également avec les tests d'intégration automatisés. Aussi des tests manuels. Heck, cela fonctionne sur les testeurs de batterie de voiture. Voici comment vous testez le test.

Certains pensent que les tests unitaires couvrent la plus petite chose pouvant être testée. Certains pensent à tout ce qui est rapide à tester. TDD est plus qu'un cycle de refactorisation vert-rouge, mais cette partie comporte 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 un changement. Pour moi, ce sont vos tests unitaires.

confits_orange
la source
1
C'est également l'une des raisons pour lesquelles les tests négatifs sont importants lorsque vous testez qu'une erreur se produit: vous voulez vous assurer que tout le reste aurait fonctionné. Par conséquent, deux tests (l'un produisant l'erreur exacte attendue, l'autre ne produisant pas l'erreur), à côté de les uns des autres contribuent à renforcer la confiance dans le maintien de cet état rouge / vert à l'avenir .
Matthieu M.
12

Cependant, je me demande si l'approche fondée sur les tests peut également s'appliquer à d'autres formes de tests.

Oui, et une approche bien connue dans ce domaine est le développement fondé sur le comportement . Les tests qui sont générés à partir des spécifications formelles dans BDD peuvent être appelés "tests unitaires", mais ils ne seront généralement pas aussi bas que dans le TDD réel, ils conviendront probablement mieux au terme "tests d'acceptation".

Doc Brown
la source
8

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

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

En fait, vous commencerez probablement par écrire un test d'acceptation ayant échoué (en rouge) pour un critère d'acceptation. Plus précisément, vous écrivez le test d'acceptation le plus simple pouvant éventuellement échouer; Ensuite, vous lancez le test, observez son échec et vérifiez qu'il échoue pour la bonne raison. Ensuite, vous écrivez un test fonctionnel ayant échoué pour une tranche de fonctionnalité de ce critère d'acceptation. Vous écrivez à nouveau le test fonctionnel le plus simple pouvant échouer, l'exécutez, surveillez son échec et vérifiez qu'il échoue pour la bonne raison. Ensuite, vous écrivez un test unitaire échouant, le test unitaire le plus simple pouvant éventuellement échouer, exécutez-le et vérifiez qu'il échoue, 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 le test à nouveau, vérifiez que le message d'erreur a bien changé, qu'il a évolué 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 et le test devrait réussir, mais le plus souvent, il est préférable de prendre de petites étapes pour changer le message plutôt que d'essayer de faire passer le test en une seule fois - c'est la raison pourquoi les développeurs de structures de test consacrent autant d’efforts à leurs messages d’erreur!)

Une fois que le test unitaire est réussi, vous reformulez votre code de production sous la protection de vos tests. (Notez que pour le moment, le test de réception et le test de fonctionnement échouent toujours, mais ce n'est pas grave, car vous ne faites que refactoriser des unités individuelles couvertes par des tests d'unités.)

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 maintenant effectuer des refactorisations sur plusieurs unités.

Ce cycle intermédiaire se répète maintenant jusqu'à ce que le test d'acceptation soit réussi. Vous pouvez alors effectuer des refactorisations sur l'ensemble du système.

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

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

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

Kent Beck dit que s'il a un test fonctionnel rapide, petit et ciblé, il écrit d'abord les tests unitaires, laisse les tests unitaires conduire le code, puis supprime à nouveau (certains) les tests unitaires qui couvrent le code également. couvert par le test fonctionnel rapide. Rappelez-vous: le code de test est aussi un code qui doit être maintenu et refactorisé, moins il y en a, mieux c'est!

Cependant, je me demande si l'approche fondée sur les tests peut également s'appliquer à 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 "conduite" de Test- Driven -Development signifie: tout votre développement est conduit par des tests. Les tests ne contrôlent pas seulement le code que vous écrivez, ils déterminent également quel code écrire et quel code écrire ensuite. Ils conduisent 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 du TDD d'oncle Bob Martin , mais beaucoup plus strictes) que vous devez suivre strictement et qui sont conçues pour vous orienter vers une application du TDD plus rigoureuse. Cela fonctionne mieux avec la programmation en binôme (pour que votre binôme puisse s’assurer que vous ne respectez pas les règles) et un instructeur.

Les règles sont:

  1. Ecrivez exactement un nouveau test, le plus petit test possible qui semble indiquer une solution
  2. Le voir échouer; les échecs de compilation comptent comme des échecs
  3. Faites le test de (1) passer en écrivant le moins de code d’implémentation que vous pouvez dans la méthode de test .
  4. Refactoriser pour supprimer les doublons, et au besoin pour améliorer la conception. Soyez strict sur l'utilisation de ces mouvements:
    1. vous voulez une nouvelle méthode — attendez l'heure du refactoring, puis… créez de nouvelles méthodes (non-test) en effectuant l'une de ces méthodes, et sans autre moyen:
      • préféré: faites Extraire la méthode sur le code d’implémentation créé conformément à (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 l'heure du refactoring, puis… créez des classes non-test pour fournir une destination à une méthode de déplacement et pour aucune autre raison
    3. remplir les classes d'implémentation avec des méthodes en faisant déplacer la méthode, et sans autre moyen

Ces règles sont destinées à l'exercice du TDD. Ils ne sont pas destinés à la réalisation de TDD en production (même si rien ne vous empêche de l'essayer). Ils peuvent se sentir frustrés parce que parfois, vous aurez l’impression de faire des milliers de minuscules petits progrès sans faire de réels progrès.

Jörg W Mittag
la source
2

TDD n'est pas du tout limité à ce que la communauté traditionnelle des tests de logiciels appelle "tests unitaires". Ce malentendu très commun est le résultat de la regrettable surcharge de Kent Beck pour le terme "unité" lors de la description de sa pratique du TDD. Ce qu'il entendait par "test unitaire" était un test exécuté isolément. Cela ne dépend pas d'autres tests. Chaque test doit configurer l'état dont il a besoin et effectuer le nettoyage éventuellement effectué. C'est en ce sens qu'un test unitaire au sens du TDD est une unité. C'est autonome. Il peut fonctionner seul ou avec n'importe quel autre test unitaire dans n'importe quel ordre.

Référence : "Le développement piloté par les tests, par exemple", par Kent Beck

Kent Beck décrit ce qu’il entend par «test unitaire» au chapitre 32 - Maîtriser le TDD.

Jason Desrosiers
la source
1

Je n'ai pas lu de livres à ce sujet ni suivi complètement les pratiques "standard" de TDD, mais dans mon esprit, le point principal de la philosophie de TDD, avec laquelle je suis tout à fait d'accord, est que vous devez d'abord définir le succès. . Ceci est important à tous les niveaux de la conception, à partir de "Quel est l'objectif de ce projet?" to "Quels devraient être les entrées et les sorties de cette petite méthode?"

Il y a beaucoup de 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 extrêmes, est d'écrire des tests en code. Pour certains niveaux d’abstraction, il peut être utile d’écrire une note rapide sur l’objectif du module, ou même simplement de vous contrôler mentalement (ou de demander à un collègue) de s’assurer que tout a du sens et est en bon état. 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 définir un plan de test rapide raisonnable que vous pouvez utiliser pour vous assurer que tous les systèmes fonctionnent ensemble. attendons.

Mais, quels que soient les techniques ou les outils spécifiques que vous utilisez, je pense que l'essentiel à retenir de la philosophie de TDD est que la définition du succès passe en premier. Sinon, vous lancez la fléchette puis vous peignez la boudine partout où elle atterrit.


la source
1

Dans la discussion Développement axé sur 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 pour la réponse). Cela inclut une étape "Écrire un test de bout en bout ayant échoué", suivie de "Écriture d'un test d'unité ayant échoué". (Cliquez pour zoomer, 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 haut niveau de bout en bout 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 sur plusieurs niveaux de la pyramide de test . 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 .

entrez la description de l'image ici

Niels van Reijmersdal
la source
-1

Non, il ne peut pas être appliqué à d'autres types de tests, pour une simple raison pratique: d'autres types de tests prennent trop de temps à s'exécuter.

Le cycle TDD typique est le suivant: test d’échec en écriture, implémentation, code de refactor. Les étapes intermédiaires consistent à créer et à exécuter des tests, qui doivent être extrêmement rapides. Si ce n'est pas le cas, les gens sautent des étapes et vous ne faites plus de TDD.

BЈовић
la source
1
Ceci est incorrect: en fonction du programme et du test (et de la langue), les tests d'intégration de bout en bout peuvent facilement s'exécuter en moins de 3 secondes. Il est tout à fait possible d'exécuter une suite de tests complète de bout en bout en très peu de temps, même si elle est bien conçue. Donc, "ne peut pas" est assez fort.
Jonathan Cast
@jcast Je n'ai jamais rien vu de plus rapide. Mes tests fonctionnels sur mon projet précédent ont pris 30 secondes, et c'est rapide. L'intégration encore plus longtemps. Dans mon cas, rien d'autre n'avait de sens. En outre, les tests unitaires sont les tests les plus rapides - il est donc logique de les utiliser.
Tous les