TDD, nouveaux tests alors que les anciens ne sont pas encore implémentés

13

J'expérimente avec le développement piloté par les tests et j'ai constaté que j'arrive souvent à la situation suivante:

  1. J'écris des tests pour certaines fonctionnalités X. Ces tests échouent.
  2. En essayant d'implémenter X, je vois que j'ai besoin d'implémenter une fonctionnalité Y dans une couche inférieure de mon code. Donc...
  3. J'écris des tests pour Y. Maintenant, les deux tests pour X et Y échouent.

Une fois, j'avais 4 fonctionnalités dans différentes couches de code travaillées en même temps, et je perdais ma concentration sur ce que je fais réellement (trop de tests échouant en même temps).

Je pense que je pourrais résoudre ce problème en mettant plus d'efforts dans la planification de mes tâches avant même de commencer à écrire des tests. Mais dans certains cas, je ne savais pas que je devrais aller plus loin, parce que, par exemple, je ne connaissais pas très bien l'API de la couche inférieure.

Que dois-je faire dans de tels cas? TDD a-t-il des recommandations?

liori
la source

Réponses:

9

La bonne chose est que vous réalisez que votre code sous test a besoin d'aide. Plutôt que de l'implémenter immédiatement, créez une interface et utilisez des simulateurs pour vous assurer que vos tests marquent le bon code. Après avoir réussi ces tests, vous pouvez ensuite passer à l'implémentation du code sur lequel il s'appuie.

Michael Brown
la source
Mes tests ne savent généralement pas ce qu'une méthode doit faire en interne (par exemple, quelle API de bas niveau appeler). Dois-je simplement ajuster les tests pour simuler tout ce dont j'ai besoin dans le code testé?
liori
2
De même, vos classes testées ne devraient pas se soucier de ce que font les «couches inférieures». Utilisez des mocks / stubs à la place des classes / objets réels. Cela peut nécessiter un peu plus d'efforts dans la conception, mais entraîne un code moins couplé et plus facile à réutiliser.
Mchl
1
Utilisez-vous l'injection de dépendance? C'est ainsi que vous pouvez facilement séparer les problèmes de niveau inférieur des classes de niveau supérieur. Votre classe en cours de test a un constructeur avec des paramètres pour ses dépendances (en tant qu'interfaces) dans votre test, vous créez des maquettes pour les interfaces. Fondamentalement, vous prétendez avoir déjà mis en œuvre les services de niveau inférieur.
Michael Brown
@ Mike Brown, oui, je le fais. Je sais que je peux créer de faux objets. Mais ensuite, dans mon test de fonctionnalité, Xje dois savoir de quelle partie des dépendances Xje dois me moquer. Je pense que cela fait partie des détails de l'implémentation, qui ne devraient pas faire partie des tests - sinon je pourrais avoir besoin de changer les tests tout en refactorisant l'implémentation. Dois-je m'en inquiéter?
liori
1
Pas du tout ... les tests doivent refléter les hypothèses du système testé. Il vous aide également à exposer ce dont vous avez besoin des services sur lesquels le système s'appuie. J'étais d'accord avec vous sur ce sujet mais je le compare à la façon dont j'ai compris la programmation récursive. Vous écrivez d'abord le code en supposant que vous avez une fonction qui fait ce que vous voulez. Ensuite, vous écrivez le code qui fait ce que vous voulez.
Michael Brown
4

Les talons et les maquettes peuvent être utilisés pour simuler la fonctionnalité qui n'est pas encore modifiée / implémentée. Ils peuvent également vous aider à résoudre les dépendances qui provoquent ce type de «réaction en chaîne».

D'un autre côté, la meilleure approche consiste peut-être à ne conserver qu'un seul test (qui échoue) à l'origine du changement suivant.

D'autres tests qui ciblent le code qui repose sur de nouvelles fonctionnalités peuvent être temporairement désactivés car ils ne sont pas vraiment pertinents à ce stade, c'est-à-dire. dans votre cas, désactivez les tests pour X jusqu'à ce que vous implémentiez Y, etc.

De cette façon, vous pouvez vous concentrer sur le prochain changement uniquement, ce qui est ce que vous voulez, je pense.

ratkok
la source
Ha, j'ai cherché une fonctionnalité pour désactiver un test lors d'un test dans mon IDE, et je n'en ai pas trouvé. Maintenant, j'ai trouvé que python a unittestdéjà un saut de test. Cela pourrait me suffire.
liori
Nous utilisons le framework google test C ++ - et il a une option pour désactiver les tests. Les tests désactivés ne sont pas exécutés mais compilés - au moment où vous en avez besoin - ils sont là prêts à être exécutés (en plus, vous pouvez `` forcer l'exécution '' des tests désactivés - sorte de `` permettre l'exécution '') - excellente fonctionnalité ...
ratkok
3

Arrêtez

À première vue, il semble qu'il puisse y avoir deux problèmes distincts ici:

  1. vous avez oublié des histoires et des scénarios de test et ne les avez pas découverts avant de commencer à travailler sur un scénario de test particulier, et / ou

  2. vous êtes en train de faire des tests unitaires, et non TDD fonction test

Pour # 1, arrêtez , revenez en arrière et mettez à jour les histoires et les scénarios de test, puis recommencez avec un scénario différent.

Pour # 2, arrêtez -vous et rappelez-vous que vous testez des fonctionnalités, pas des unités, alors utilisez des simulateurs pour masquer d'autres interfaces et / ou implémentez plus de code pour réussir le test sans ajouter de nouveaux scénarios de test. Cela suppose que vous ne manquez pas de scénarios de test, mais que vous êtes plutôt - et cela est vraiment courant - en combinant les tests unitaires et TDD.

Steven A. Lowe
la source
J'aime vraiment votre réponse, elle explique mieux ce qui se passe réellement.
maple_shaft
... Cela étant dit, je ne connais pas de Premier Ministre au monde qui ne perdra pas complètement la tête à la phrase "STOP, nous devons faire marche arrière". Ils essaieront tout sauf de sacrifier leur premier-né à l'autel pour faire avancer le projet, la dette technique et les tests unitaires incomplets seront damnés. Je suppose que vous ne pouvez pas les blâmer lorsque leur seule mesure dans une organisation est de terminer le projet à temps. Certaines organisations apprécient le temps plutôt que la qualité et c'est pourquoi je n'ai probablement jamais vu TDD fonctionner avec succès dans ces types d'organisations, qui sont malheureusement LA PLUPART d'entre elles de l'OMI.
maple_shaft
@maple_shaft: la durée pendant laquelle vous vous arrêtez pour vous regrouper ne peut être que de quelques heures - à moins que votre processus ne soit trop éloigné de la base, auquel cas un arrêt de quelques jours pour le remettre sur les rails rendra beaucoup plus probable que le projet réussira. Il ne sert à rien d'aller à toute vapeur sur la mauvaise voie!
Steven A. Lowe
0

C'est une grande question et une énorme frustration pour moi aussi avec TDD. J'ai l'impression que TDD manque dans ce scénario où vous n'avez tout simplement aucun moyen de savoir de quels composants ou fonctionnalités de niveau inférieur vous aurez besoin jusqu'à ce que vous commenciez à développer.

Personnellement, j'ai trouvé que TDD ne fonctionne que si vous savez exactement ce que vous devez faire et ce que vous devez appeler pour exécuter une fonction. Les développeurs ne savent pas toujours tout avant de commencer, j'ai donc trouvé que la meilleure façon pour moi d'atténuer la situation même que vous décrivez:

Prototype

Lorsque je crée de simples applications prototypes pour explorer et découvrir des méthodes et des approches à un problème technique, je découvre une grande partie du travail sur les jambes et élimine ces recherches avant de commencer. La conception et l'estimation deviennent également beaucoup plus faciles.

Si le prototype doit être si impliqué qu'il devient l'application, je vous exhorte cependant à ne pas faire la chose paresseuse et à construire des tests unitaires pour votre prototype après coup.

À ce stade, vous devez en savoir plus sur l'API de niveau inférieur et être en mesure de simuler avec succès l'API de niveau inférieur dans vos composants de niveau supérieur.

maple_shaft
la source
Vous proposez donc en fait d'obtenir plus d'informations pour la phase de planification en effectuant un codage exploratoire de manière informelle (= ne pas suivre une méthodologie formalisée). Et puis supposez qu'il fournira suffisamment d'informations pour planifier le vrai code. Ai-je raison?
liori
Pourquoi présumez-vous que le prototypage est un processus informel? Chaque estimation doit tenir compte du prototypage et les calendriers de projet doivent en tenir compte ainsi qu'une tâche de développement nécessaire. Je le vois de la même façon que Design ou Code-Review. Sur cette note, il est formalisé et devrait être pris en compte, encore plus sur les tâches avec beaucoup d'inconnues. Sans prototypage et sans la possibilité d'effectuer une validation de principe, poursuivre TDD suppose simplement que les développeurs connaissent TOUT sur TOUT avec TOUTES les fonctionnalités. Le monde réel ne fonctionne pas de cette façon et je me fiche de votre intelligence ou de votre expérience.
maple_shaft
Par «voie informelle», je ne voulais pas dire que le temps pour le prototypage ne devrait pas être pris en compte, mais que pendant que vous faites des prototypes, vous ne suivez pas TDD ou toute autre méthodologie de code.
liori
TDD est une méthodologie pour les tests unitaires et le développement. Serait-il judicieux de faire TDD pour la révision du code? TDD a-t-il un sens pour la conception, la rédaction des spécifications techniques ou le tableau blanc? Le prototypage est une tâche en soi, un type de développement exploratoire pour la recherche, la preuve de concept et l'éducation.
maple_shaft
1
TDD est parfaitement logique pour le prototypage. Il vous permet d'exposer rapidement les éléments de votre contenu (objet, fonction, API, programme entier) sous la forme d'un ensemble d'exigences répétable et exécutable. Rendez-vous service et lisez Growing Object Oriented Software Guided by Tests ; il vous guide pas à pas à travers la construction d'une application entière (y compris l'intégration) de manière test-first.
Frank Shearar
0

Cela dépend du type de tests que vous écrivez en faisant TDD.

Le modèle classique consiste à écrire des tests unitaires et à utiliser des simulations ou des talons pour dissocier le test des autres "unités" de code.

Il existe de nombreux autres modèles alternatifs tels que ATDD où le test d'une pile complète, ou un test de pile presque complète. Dans ce cas particulier, vos tests d'écriture qui affirment le comportement du programme requis ne constituent pas une seule unité de code, vous n'écrirez donc pas d'autres tests. Vous obtiendrez la mise en œuvre de l'aller-retour pour satisfaire le test. Vous ajoutez ensuite d'autres tests pour d'autres fonctionnalités / comportements.

Dietbuddha
la source