Pourquoi TDD fonctionne-t-il? [fermé]

92

Le développement piloté par les tests (TDD) est important ces jours-ci. Je le vois souvent recommandé comme solution à un large éventail de problèmes ici, dans Programmers SE et d’autres lieux. Je me demande pourquoi ça marche.

D'un point de vue technique, cela m'interpelle pour deux raisons:

  1. L'approche "test d'écriture + refactorisation jusqu'au passage" est incroyablement anti-ingénierie. Si les ingénieurs civils utilisaient cette approche pour la construction de ponts ou les concepteurs de voitures pour leurs voitures, par exemple, ils seraient en train de remodeler leurs ponts ou leurs voitures à un coût très élevé, et le résultat serait un gâchis rafraîchi sans architecture bien pensée. . La directive «refactor till pass» est souvent considérée comme un mandat pour oublier la conception architecturale et faire tout ce qui est nécessaire pour se conformer au test. En d'autres termes, le test, plutôt que l'utilisateur, définit l'exigence. Dans cette situation, comment pouvons-nous garantir de bonnes «compétences» dans les résultats, c’est-à-dire un résultat final non seulement correct, mais également extensible, robuste, facile à utiliser, fiable, sûr, sécurisé, etc.? C'est ce que fait habituellement l'architecture.
  2. Les tests ne peuvent pas garantir le fonctionnement d'un système. cela ne peut que montrer que ce n'est pas le cas. En d'autres termes, les tests peuvent vous montrer qu'un système contient des défauts s'il échoue à un test, mais un système qui réussit tous les tests n'est pas plus sûr qu'un système qui les échoue. La couverture de test, la qualité du test et d'autres facteurs sont cruciaux ici. Les faux sentiments de sécurité qu'un "tout vert" produit chez de nombreuses personnes ont été signalés dans les industries civile et aérospatiale comme extrêmement dangereux, car ils peuvent être interprétés comme "le système va bien", alors que cela signifie réellement "le système est aussi bon comme stratégie de test ". Souvent, la stratégie de test n'est pas vérifiée. Ou, qui teste les tests?

En résumé, je suis plus préoccupé par le bit "piloté" dans TDD que par le bit "test". Le test est parfaitement correct; ce que je ne comprends pas, c'est le pilotage du design en le réalisant.

J'aimerais voir des réponses contenant les raisons pour lesquelles TDD en génie logiciel est une bonne pratique et pourquoi les problèmes que j'ai expliqués ci-dessus ne sont pas pertinents (ou pas assez pertinents) dans le cas d'un logiciel. Je vous remercie.

CesarGon
la source
53
Les ponts, les voitures et autres conceptions physiques sont loin d'être aussi malléables que les logiciels. Cette distinction est importante et signifie que les comparaisons entre logiciel et ingénierie réelle ne sont pas toujours pertinentes. Ce qui fonctionne pour les ponts peut ne pas fonctionner pour les logiciels, et inversement.
Lars Wirzenius
9
Je suis un peu d'accord avec vos doutes. Par exemple, je dois avouer que j’ai l’impression qu’avoir une suite de tests peut avoir pour effet secondaire d’attirer l’attention sur l’attention lors de l’écriture de code. Bien sûr, les tests sont une bonne chose (obligatoire si vous voulez avoir la possibilité de refactoriser), mais seulement s’ils complètent l’attention portée aux détails, les cas-frontières, l’efficacité ou l’extensibilité et non s’ils le remplacent.
6502
2
@ 6502: Certainement! TDD n’est pas une solution miracle et ne résoudra pas tous les problèmes rencontrés lors du développement de logiciels. C'est cependant une méthode utile pour organiser le flux de travail. Vous pouvez par exemple imposer une condition selon laquelle tous les cas frontaliers sont couverts par des tests. Vous devez toujours savoir ce que sont ces cas de frontière, mais vous disposez maintenant d'un outil pour vérifier si votre code les traite correctement.
Mchl
2
@ CesarGon, vous pourriez aussi être intéressant avec cette question que j'ai posée à SO il y a quelque temps ... Pas tout à fait TDD, mais liée ... Quelques réponses très éclairantes là-bas.
AviD
6
Quelle merveille qu'un analogue de génie civil / développement de logiciel ne tienne pas. Dans le même ordre d'idées, j'ai souvent remarqué que je ne pouvais pas cuisiner des pancakes de la même façon que je tondais ma pelouse.

Réponses:

66

Je pense qu'il y a une idée fausse ici. Dans la conception de logiciels, la conception est très proche du produit. En génie civil et en architecture, la conception est dissociée du produit réel: il existe des plans qui maintiennent la conception, qui sont ensuite matérialisés dans le produit fini, et qui sont séparés par une énorme quantité de temps et d’efforts.

TDD teste la conception. Mais chaque conception de voiture et de construction est également testée. Les techniques de construction sont d'abord calculées, puis testées à plus petite échelle, puis à plus grande échelle, avant d'être installées dans un bâtiment réel. Quand ils ont inventé les poutres en H et la charge, par exemple, ils se sont assurés que cela avait été essayé et réessayé avant, ils ont construit le premier pont avec celui-ci.

Les conceptions de voitures sont également testées, en concevant des prototypes et, bien sûr, en ajustant des éléments qui ne sont pas tout à fait corrects, jusqu'à ce qu'ils soient à la hauteur des attentes. Une partie de ce processus est cependant plus lente, car comme vous l'avez dit, vous ne pouvez pas jouer avec le produit. Mais chaque refonte d'une voiture s'appuie sur les expériences acquises et chaque bâtiment s'appuie sur environ mille ans de principes fondamentaux concernant l'importance de l'espace, de la lumière, de l'isolation, de la résistance, etc. Les détails sont modifiés et améliorés, à la fois dans les bâtiments et dans la refonte pour les plus récents.

En outre, les pièces sont testées. Peut-être pas exactement dans le même style que le logiciel, mais les pièces mécaniques (roues, allumeurs, câbles) sont généralement mesurées et soumises à des contraintes pour savoir si les tailles sont correctes, aucune anomalie ne doit être constatée, etc. mesurés, ils tapent des briques pour en repérer des brisées, ils peuvent en fait être testés dans une configuration ou une autre, ou ils dessinent une représentation limitée d’un grand groupe pour le mettre réellement à l’épreuve.

Ce sont toutes les choses que vous pouvez mettre en place avec TDD.

Et en effet, les tests ne sont pas une garantie. Les programmes se bloquent, les voitures tombent en panne et les bâtiments commencent à faire des choses amusantes lorsque le vent souffle. Mais ... la "sécurité" n'est pas une question booléenne. Même quand on ne peut pas tout inclure, pouvoir couvrir - disons - 99% des éventualités est mieux que couvrir seulement 50%. Ne pas tester et ensuite découvrir que l'acier n'est pas bien réglé, qu'il est fragile et qu'il se casse au premier coup de marteau lorsque vous venez de mettre en place votre structure principale est un gaspillage d'argent. Le fait que d’autres problèmes puissent encore nuire au bâtiment ne le rend pas moins stupide de permettre à un défaut facilement évitable de nuire à votre conception.

En ce qui concerne la pratique du TDD, il s’agit d’un problème d’équilibre. Le coût pour le faire d'une manière (par exemple, ne pas tester, puis récupérer les éléments plus tard), par rapport au coût d'une autre manière. C'est toujours un équilibre. Mais ne pensez pas que d’autres processus de conception n’ont pas de tests et de TDD en place.

Inca
la source
7
+1 pour parler de l'endroit où sont effectués les tests en fabrication. Excellent point.
Adam Lear
11
Vous dites "les pièces sont testées". Bien sûr, mais pas conçu à l’essai. Une pièce d'aéronef n'est pas conçue de manière testée, mais de manière architecturale et de grande conception. Les similitudes avec TDD sont inexistantes ici.
CesarGon
3
Ajoutons à cela: TDD est, à mon avis, principalement un moyen de s’assurer que vous pouvez vérifier les pièces plutôt qu’un gros «tout ou rien» à la fin. Mais l'adagium de TDD, «construire un test en premier», ne signifie pas «faire un test avant de penser à ce que vous voulez accomplir». Parce que penser à un test fait partie de la conception. Spécifier ce que vous voulez que cette partie exacte fasse, c'est concevoir. Avant que vous ne commenciez à taper, vous avez déjà fait de la conception. (De cette façon, je pense que le terme «conception pilotée par les tests» implique de manière trompeuse un chemin de navigation aller simple, où il s’agit en réalité d’une boucle de rétroaction).
Inca
2
+1: le logiciel est purement design. L'analogie de bridge dans la question est complètement fausse. TDD applique totalement les tests unitaires extérieurs. La conception pilotée par les tests s'applique à toutes les couches de la conception.
S.Lott
3
@ CesarGon: Non, TDD pilote le DÉVELOPPEMENT en testant. C'est différent de piloter le design. La conception dicte la manière dont vous utiliserez le système et, par conséquent, les tests à implémenter pour répliquer ce comportement. La mise en œuvre de ces tests vous aide souvent à affiner la conception.
deworde
26

OMI, la plupart des histoires de réussite de TDD sont fausses et uniquement à des fins de marketing. Il peut y avoir très peu de succès avec cela, mais seulement pour de petites applications. Je travaille sur une grande application Silverlight où les principes de TDD sont utilisés. L'application a eu des centaines de tests mais elle n'est toujours pas stable. Plusieurs parties de l'application ne sont pas testables en raison des interactions complexes entre l'utilisateur. Tests résultants avec beaucoup de simulacres et de code difficile à comprendre.

Au début, lorsque nous avons essayé le TDD, tout semble bien aller. J'ai été capable de rédiger de nombreux tests et de simuler les éléments difficiles à tester à l'unité. Une fois que vous avez une bonne quantité de code et qu'un changement d'interface est requis, vous êtes foutu. Un grand nombre de tests doivent être corrigés et vous devrez réécrire plus de tests que la modification réelle du code.

Peter Norvig explique son point de vue sur le TDD dans le livre Coders At Work.

Seibel: Qu'en est-il de l'idée d'utiliser des tests pour piloter la conception?

Norvig: Je vois davantage les tests comme un moyen de corriger les erreurs que comme un moyen de concevoir. Cette approche extrême consistant à dire: «Eh bien, la première chose à faire est d’écrire un test qui dit que j’obtiens la bonne réponse à la fin», puis vous le lancez et voyez qu’il échoue, puis vous dites: «Que puis-je faire? besoin ensuite? »- cela ne semble pas être la bonne façon de concevoir quelque chose pour moi. Il semble que si cela était si simple que la solution soit pré-ordonnée, cela aurait du sens. Je pense que vous devez y penser d'abord. Vous devez dire: «Quelles sont les pièces? Comment puis-je écrire des tests pour des morceaux jusqu'à ce que je sache quels sont certains d'entre eux? »Et ensuite, une fois que vous avez fait cela, il est alors bon de procéder à des tests pour chacun de ces morceaux et de bien comprendre comment ils interagissent les uns avec les autres. et les cas limites et ainsi de suite. Ceux-ci devraient tous avoir des tests. Mais je ne pense pas que vous dirigiez toute la conception en disant: «Ce test a échoué».

Navaneeth KN
la source
7
Maintenant, si vous racontez ces faits aux gens de TDD et aux consultants, vous obtiendrez la réponse suivante:well, you haven't done TDD right!
Navaneeth KN le
10
Et ils auraient raison. Nous travaillons sur BDD / TDD sur un système à très fort volume et cela fonctionne bien. Les tests sont là pour vous dire que vous avez brisé le comportement attendu. Si vous envisagez de changer les tests plus tard, vous vous trompez. Les tests doivent d'abord être modifiés pour confirmer le comportement NEW du système, puis vous le changez. Et oui, si vous le faites bien, vous écrivez vos tests en commençant par «qu'est-ce que cette chose doit faire» et le processus de rédaction du test vous aide à penser «de quoi l'informatique a-t-elle besoin pour faire son travail». Oh, et aucun consultant n'a jamais été utilisé ...
Andy
4
Faire beaucoup de tests ne vous dispense pas de créer un design adéquat. Une conception hautement couplée, quel que soit le nombre de tests construits autour de celle-ci, sera toujours fragile. l'intégration de tests dans cette conception peut très bien rendre le tout encore pire.
Newtopian
3
Il ne s'agit pas de mal faire ou d'être une conception hautement couplée. Le fait est que les interfaces changent. Cela signifie que tous les tests utilisant cette interface doivent changer. Sur les grands systèmes, la synchronisation des tests avec les modifications requises peut entraîner une surcharge de mise en œuvre. Cela devient un problème encore plus important si vous effectuez un développement agile car les chances de changements d'interface sont beaucoup plus probables. C'est drôle de voir comment, lorsque les méthodologies ne fonctionnent pas, les partisans de la méthodologie insistent pour que vous le fassiez mal. Il est plus probable que la méthodologie ne convient pas à tous les problèmes.
Dunk
2
Dans mon expérience, TDD fonctionne pour de petites applications ou modules. Lorsque je dois travailler sur quelque chose de complexe, le TDD me ralentit parce que cela me force à écrire une spécification détaillée (exécutable) avant que je ne voie clairement dans mon esprit: je me perds trop tôt dans les détails, et souvent je dois Jeter tout un tas de tests si je découvre que je n'ai pas besoin de certaines classes (je joue toujours avec le design). Dans de tels cas, je préfère commencer par obtenir une conception globale raisonnable, puis préciser les détails de la mise en œuvre (éventuellement à l'aide de TDD).
Giorgio
25

Test Driven Design fonctionne pour moi pour les raisons suivantes:

C'est une forme exécutable de la spécification.

Cela signifie que vous pouvez voir à partir des cas de test:

  1. QUE le code appelé étant complet remplit la spécification car les résultats attendus sont là dans les cas de test. L'inspection visuelle (qui s'attend à ce que les cas de test réussissent) peut immédiatement indiquer "oh, ce test vérifie que l'appel de invoiceCompany étant donné cette situation, devrait avoir CE résultat".
  2. COMMENT le code doit être appelé. Les étapes nécessaires pour effectuer les tests sont spécifiées directement, sans aucun échafaudage externe (les bases de données sont maquillées, etc.).

Vous écrivez la vue de l'extérieur en premier.

Le code est souvent écrit d'une manière où vous d' abord résoudre le problème, et que vous pensez de la façon dont le code que vous venez d' écrire est d'être appelé. Cela donne souvent une interface inconfortable, car il est souvent plus facile de "simplement ajouter un drapeau", etc. En pensant que "nous devons faire ceci pour que les cas de test ressemblent à CELA" dès le départ, vous inversez la situation. Cela donnera une meilleure modularité, car le code sera écrit en fonction de l'interface appelante, et non l'inverse.

Cela se traduira généralement également par un code plus propre nécessitant moins de documentation explicative.

Vous êtes fait plus vite

Puisque vous avez la spécification sous forme exécutable, vous avez terminé lorsque la suite de tests complète est terminée. Vous pouvez ajouter d'autres tests au fur et à mesure que vous clarifiez les choses, mais vous avez comme principe de base un indicateur très clair et visible des progrès accomplis.

Cela signifie que vous pouvez savoir si un travail est nécessaire ou non (est-ce que cela vous aide de réussir un test), vous finissez par avoir besoin de faire moins.

Pour ceux qui y pensent, cela peut leur être utile, je vous encourage à utiliser TDD pour votre prochaine routine de bibliothèque. Définissez lentement une spécification exécutable et faites en sorte que le code passe les tests avec succès. Une fois terminé, la spécification exécutable est disponible pour tous ceux qui ont besoin de savoir comment appeler la bibliothèque.

Étude récente

"Les résultats des études de cas indiquent que la densité de défauts avant publication des quatre produits a diminué entre 40% et 90% par rapport à des projets similaires qui n'utilisaient pas la pratique du TDD. Subjectivement, les équipes ont connu une augmentation de 15 à 35% temps de développement initial après l’adoption du TDD. " ~ Résultats et expériences de 4 équipes industrielles

Dave Jarvis
la source
5
J'ajouterais à cela que vous avez en réalité une directive assez raisonnable et claire sur le moment où vous avez terminé. Sans une procédure claire pour vérifier de manière objective que vous avez terminé la tâche à accomplir, il est difficile de le savoir. Ma propre expérience inclut de nombreuses heures et jours perdus à "négocier" si une tâche a été complétée et à un déplacement continu et constant de la ligne. Cela a une incidence sur tous les niveaux de gestion de projet, y compris la planification, car comment pouvez-vous éventuellement planifier une telle tâche? Des cibles plus claires avec un délai d'exécution plus rapide augmentent le débit ET la communication.
Edward Strange
Cela devrait être la réponse acceptée.
Niing
19

Le processus de création d'un logiciel n'est pas le processus d'écriture du code. Aucun projet logiciel ne devrait commencer sans un plan «à portée étendue». Tout comme un projet de pontage entre deux rives d’une rivière nécessite un tel plan d’abord.

L’approche TDD concerne (principalement) les tests unitaires (du moins c’est ce que les gens ont tendance à penser), ce qui crée les bits de code logiciel les plus bas. Lorsque toutes les caractéristiques et tous les comportements ont déjà été définis et que nous savons réellement ce que nous voulons atteindre.

En ingénierie structurelle, cela ressemble un peu à ceci:

«Nous avons ces deux pièces de métal reliées ensemble et la connexion doit supporter des forces de cisaillement de l'ordre de x. Testons quelle méthode de connexion est la meilleure pour le faire '

Pour tester si le logiciel fonctionne dans son ensemble, nous concevons d'autres types de tests, tels que des tests d'utilisabilité, des tests d'intégration et des tests d'acceptation. Celles-ci doivent également être définies avant le début du travail d’écriture du code et sont exécutées une fois que les tests unitaires sont verts.

Voir le modèle V: http://en.wikipedia.org/wiki/V-Model_%28software_development%29

Voyons comment cela fonctionnerait pour un pont:

  1. Un gouvernement local déclare à une entreprise de construction de ponts: «Nous avons besoin d’un pont pour relier ces deux points. Le pont doit pouvoir permettre un trafic important par heure et être prêt pour le 21 décembre 2012 '- c’est une définition de test d’acceptation. L’entreprise n’obtiendra pas le montant total (ou aucune somme) si elle ne réussit pas ce test.

  2. La direction de la société décide du calendrier du projet. Ils mettent en place des équipes de travail et fixent des objectifs pour chaque équipe. Si les équipes n'atteignent pas ces objectifs, le pont ne sera pas construit à temps. Cependant - il y a un certain niveau de flexibilité ici. Si l'une des équipes rencontre des problèmes, l'entreprise peut compenser cela en changeant les exigences, en changeant de sous-traitants, en embauchant plus de personnel, etc., de sorte que l'ensemble du projet atteigne toujours l'objectif défini au point 1.

  3. Dans une équipe responsable de la conception de composants de ponts particuliers, cela ressemble à l'exemple que j'ai donné ci-dessus. Parfois, la solution est évidente, car nous possédons un vaste corpus de connaissances en matière de création de ponts (c'est comme utiliser une bibliothèque bien testée pour le développement de logiciels - vous supposez simplement que cela fonctionne comme annoncé). Parfois, vous devez créer plusieurs modèles et les tester pour choisir le meilleur. Néanmoins, les critères sur lesquels le composant est testé sont connus à l’avance.

Mchl
la source
Si je vous ai bien compris, vous dites que le TDD est acceptable dans la mesure où (a) il est utilisé uniquement pour des tests unitaires et (b) qu’il est accompagné d’autres méthodes de test. Si tel est le cas, il peut s’adresser au point 2 de l’OP. Comment aborderiez-vous le point 1?
CesarGon
@CesarGon: TDD fonctionne également très bien pour les tests d'intégration.
Sevenseacat
Le point 1 se résume à la loi, à savoir qu'avant l'acceptation du projet final d'une voiture ou d'un pont, il est soumis à de nombreuses répétitions au cours desquelles tous ses détails sont examinés et testés par rapport aux exigences imposées par le "plan à large portée". Cela se fait principalement sur papier (ou dans la mémoire de l'ordinateur), parce que c'est moins cher dans ce cas, mais remarquez que des prototypes physiques sont souvent construits à la fois de la construction entière (pas dans un boîtier de pont) et de ses composants.
Mchl
@Karpie: Et pour les tests d'acceptation aussi! Vous devez savoir à l'avance ce qui est requis pour que votre travail soit accepté par le client.
Mchl
1
Alors ok. La quasi-première équipe à commencer les travaux est une équipe d'architectes à qui il est demandé de concevoir un pont capable de répondre aux critères des clients, tout en étant aussi bon marché et sans doute en bon état, sans pour autant s'effondrer à la première rafale. L’équipe peut proposer quelques brouillons répondant plus ou moins à ces critères, puis en sélectionner un et l’étudier plus en détail, répéter, répéter, répéter jusqu’à ce que le dessin soit prêt (c’est-à-dire qu’il répond aux critères donnés et est suffisamment détaillé pour que une autre étape du projet peut commencer)
Mchl le
18

Dans mon esprit, TDD fonctionne parce que

  • Il vous oblige à définir ce que vous voulez que l'unité fasse avant de décider de la mise en œuvre avec un niveau de précision qui n'est généralement pas couvert par un document de spécification ou d'exigences.
  • Cela rend votre code intrinsèquement réutilisable, car vous devez l'utiliser à la fois dans les tests et dans les scénarios de production.
  • Il vous encourage à écrire du code dans une taille plus petite pour tester des morceaux, ce qui tend à améliorer les conceptions.

Plus précisément sur les points que vous soulevez

  • Le code est plus malléable que la brique ou l’acier, il est donc moins coûteux de le modifier. C'est encore moins cher si vous avez des tests pour vous assurer que le comportement est inchangé
  • TDD n’est pas une excuse pour ne pas faire de design - une architecture de haut niveau est toujours recommandée, mais pas trop détaillée. Big Up Front Design est déconseillé, mais il est recommandé de faire juste assez de design.
  • TDD ne peut pas garantir le bon fonctionnement d'un système, mais il évite de nombreuses petites erreurs qui pourraient autrement nous échapper. De plus, parce qu'il encourage généralement un code mieux factorisé, il est souvent plus facile à comprendre, donc moins susceptible d'être bogué.
Gavin Clarke
la source
3
Vous devez également ajouter que lorsque les défauts sont découverts, vous pouvez vous assurer qu'ils ne se reproduiront pas, car vous ajouterez un autre test.
Andy
16

TL; DR

La programmation est toujours une activité de conception, ce n'est pas de la construction. Écrire des tests unitaires après coup ne fait que confirmer que le code fait ce qu’il fait, mais pas qu’il fait quelque chose d’utile. Les échecs de test sont la valeur réelle, car ils vous permettent de détecter les erreurs plus tôt.

Code is Design

Au chapitre 7 du PPP, "Oncle Bob" parle directement de cette question. Très tôt dans le chapitre, il fait référence à un excellent article de Jack Reeves dans lequel il propose que le code soit du design (le lien renvoie à une page rassemblant les trois de ses articles sur le sujet).

Ce qui est intéressant à propos de cet argument, c’est ce qu’il souligne, contrairement à d’autres disciplines de l’ingénierie où la construction est une activité très coûteuse, la construction de logiciels est relativement libre (cliquez sur Compile dans votre IDE et vous avez votre logiciel construit). Si vous considérez l'écriture de code comme une activité de conception plutôt que comme une activité de construction, le cycle rouge-vert-refactorisation est fondamentalement un exercice de conception. Votre conception évolue au fur et à mesure que vous écrivez des tests, le code pour les satisfaire et un refactor pour intégrer le nouveau code dans le système existant.

TDD comme spécification

Les tests unitaires que vous écrivez pour TDD sont une traduction directe de la spécification telle que vous la comprenez. En écrivant du code qui satisfait au minimum votre spécification (fait passer vos tests au vert), tout le code que vous avez écrit est destiné à un but spécifique. Que cet objectif soit atteint ou non est validé par un test répétable.

Écrire des tests à la fonctionnalité

Une erreur commune dans les tests unitaires se produit lorsque vous écrivez les tests après le code, vous finissez par tester que le code fait ce qu'il fait. En d'autres termes, vous verrez des tests comme celui-ci

public class PersonTest:Test
{
   [Test]
   TestNameProperty()
   {
      var person=new Person();
      person.Name="John Doe";
      Assert.AreEqual("John Doe", person.Name);
   }
}

Bien que je suppose que ce code puisse être utile (assurez-vous que quelqu'un n'a pas fait quelque chose d'obscène avec une propriété simple). Cela ne sert pas à valider une spécification. Et comme vous l'avez dit, l'écriture de ce type de tests ne vous mène pas loin.

Bien que le vert soit bon, la valeur réside en rouge J'ai eu mon premier vrai vrai "aha" en TDD quand j'ai eu un échec de test inattendu. J'ai eu une série de tests que j'ai eu pour un cadre que je construisais. Ajoutant une nouvelle fonctionnalité, j'ai écrit un test pour cela. Puis écrit le code pour faire passer le test. Compilez, testez… obtenez le vert sur le nouveau test. Mais aussi un rouge sur un autre test que je ne pensais pas devenir rouge.

En regardant l'échec, je soupire de soulagement parce que je doute que j'aurais attrapé ce virus pendant un bon bout de temps si je n'avais pas eu ce test en place. Et c'était un très mauvais insecte à avoir. Heureusement, j'ai passé le test et il m'a dit exactement ce que je devais faire pour résoudre le problème. Sans le test, j'aurais continué à construire mon système (le bogue infectant d'autres modules dépendant de ce code) et au moment où le bogue aurait été découvert, il aurait été très difficile de le corriger correctement.

Le véritable avantage de TDD est qu’il nous permet d’apporter des modifications avec un abandon inconsidéré. C'est comme un filet de sécurité pour la programmation. Pensez à ce qui se produirait si un trapéziste commettait une erreur et tombait. Avec le net, c'est une erreur embarrassante. Sans ça, c'est une tragédie. De la même manière, TDD vous évite de transformer des erreurs démesurées en désastres qui tuent des projets.

Michael Brown
la source
4
La valeur des tests rouges qui détectent les bogues est un attribut du test unitaire en général, pas du TDD en particulier.
Robert Harvey le
2
Vous avez raison sur ce point. Mais la probabilité que ce bug spécifique soit couvert par des tests unitaires post-hoc est moindre.
Michael Brown
1
Pouvez-vous appuyer cette affirmation avec des preuves, des données ou une analyse solide?
CesarGon
1
@CesarGon cette étude , alors que des programmeurs travaillant sur un petit projet, suggère que les développeurs utilisant TDD produisent du code avec une meilleure couverture de test que ceux qui testent après coup (92% à 98% par rapport à 80% à 90%) défauts au cours du développement (18% moins de défauts trouvés dans le code produit avec TDD).
Jules
11

Vous ne trouverez personne qui prône le développement piloté par les tests, ni même la conception pilotée par les tests (ils sont différents), qui dit que les tests prouvent les applications. Alors appelons cela un homme de paille et le tour est joué.

Vous ne trouverez personne qui n'aime pas ou ne soit pas impressionné par le TDD qui affirme que les tests sont une perte de temps et d’effort. Bien que les tests ne prouvent pas les applications, ils sont très utiles pour détecter les erreurs.

Ces deux choses étant dites, aucune des deux parties ne fait autre chose pour effectuer des tests sur le logiciel. Les deux font des tests. Les deux font confiance aux tests pour trouver autant de bogues que possible, et utilisent des tests pour vérifier qu'un logiciel fonctionne aussi bien qu'il est possible de le découvrir à ce moment-là. Personne avec un demi-indice ne vend de logiciel sans avoir à tester et personne avec un demi-indice ne s'attend à ce que le test vienne rendre le code qu'ils vendent complètement sans mémoire.

Ainsi, la différence entre TDD et non-TDD n'est pas que des tests sont en cours. La différence réside dans la rédaction des tests. En TDD, les tests sont écrits AVANT le logiciel. Dans les tests non-TDD, les tests sont écrits après ou de concert avec le logiciel.

Le problème que j’ai vu concernant ce dernier point est que les tests ont alors tendance à cibler le logiciel en cours d’écriture plus que le résultat ou les spécifications souhaitées. Même si l'équipe de test est séparée de l'équipe de développement, cette dernière a tendance à examiner le logiciel, à l'utiliser et à écrire des tests qui le ciblent.

Ceux qui étudient le succès d'un projet ont remarqué à maintes reprises combien de fois un client exposait ce qu'il souhaitait, les responsables du développement s'en sortaient et écrivaient quelque chose, et lorsqu'ils revenaient au client en lui disant qu'ils avaient terminé. il s'avère que ce n'est absolument pas ce que le client a demandé. "Mais il passe tous les tests ..."

Le but de TDD est de casser cet "argument circulaire" et de fournir une base pour les tests qui testent un logiciel autre que le logiciel lui-même. Les tests sont écrits pour cibler le comportement souhaité par le "client". Le logiciel est ensuite écrit pour réussir ces tests.

TDD fait partie de la solution destinée à résoudre ce problème. Ce n'est pas la seule étape que vous faites. Vous devez également vous assurer que les commentaires des clients sont plus nombreux et plus fréquents.

Dans mon expérience cependant, TDD est une chose très difficile à mettre en œuvre avec succès. Il est difficile d'obtenir des tests écrits avant qu'un produit ne soit créé, car de nombreux tests automatisés nécessitent de jouer avec quelque chose pour que le logiciel d'automatisation fonctionne correctement. Il est également difficile de convaincre les développeurs qui ne sont pas habitués aux tests unitaires de le faire. Maintes et maintes fois, j'ai dit aux membres de mon équipe d'écrire les tests EN PREMIER. Je n'ai jamais vraiment eu quelqu'un pour le faire. En fin de compte, les contraintes de temps et la politique ont détruit tous les efforts, de sorte que nous ne faisons même plus de tests unitaires. Bien entendu, cela a inévitablement conduit à un couplage fort et accidentel de la conception, de sorte que même si nous le voulions, sa mise en œuvre serait désormais trop coûteuse. C’est finalement ce que TDD propose aux développeurs.

Edward Strange
la source
+1 Merci pour la réponse complète, Noah. Je conviens que la différence majeure entre TDD et non-TDD réside dans le moment où les tests sont écrits. Cependant, je pense aussi que le premier "D" dans TDD signifie "driven", ce qui signifie que, dans TDD, tout le développement est conduit par les tests. C'est ce que je trouve le plus déconcertant. Je n'ai aucun problème à écrire des tests avant de construire réellement ce qui va être testé. Mais laisser les tests conduire? En quoi est-ce différent d’un feu vert de faire quelque chose tant que le résultat superficiel (c’est-à-dire le résultat) est acceptable?
CesarGon
Eh bien, Cesar, que proposeriez-vous comme meilleur critère objectif pour décider du moment où une tâche de développement est terminée? Si, comme dans TDD, le test est la spécification qu'un développeur cible, alors le développeur a fait son travail lorsque le test est réussi, non? Oui, il peut y avoir des défauts dans le test, tout comme dans n'importe quelle spécification. Ce n'est pas la tâche des développeurs à résoudre cependant. Si le test est défectueux, il est corrigé, puis le développement cible la nouvelle cible et est entièrement terminé lorsqu'il est vert. Cela fonctionne parce qu'il y a TOUJOURS un test à passer ... pas de bourre supplémentaire non documentée.
Edward Strange
3
Peut-être que je ne me suis pas exprimé clairement. Les tests peuvent être un bon moyen de déterminer quand vous avez terminé. Mais je ne pense pas que ce soit un bon moyen de décider de ce que vous devez construire. Et, dans TDD, je trouve que les gens utilisent des tests pour décider de ce qu’ils sont censés construire. Est-ce aussi votre expérience?
CesarGon
Non, nos constructions sont automatisées. Ils sont déclenchés par des changements. Comme je l'ai dit, le TDD n'est qu'une partie de la solution.
Edward Strange
9

Concevoir d'abord

TDD n’est pas une excuse pour ignorer la conception. J'ai vu beaucoup de gens se lancer dans le mouvement "agile" parce qu'ils pensaient pouvoir commencer à coder immédiatement. Une véritable agilité vous amènera au codage statistique beaucoup plus rapidement que les bonnes pratiques d'ingénierie (autres domaines) qui ont inspiré le processus de cascade.

Mais testez tôt

Quand on dit que les tests pilotent la conception, cela signifie simplement que l'on peut utiliser des tests très tôt dans la phase de conception, bien avant que celle-ci ne soit terminée. Faire ces tests va fortement influencer votre conception en défiant les zones grises et en la confrontant au monde réel bien avant l’achèvement du produit. vous obligeant souvent à revenir à la conception et à l’ajuster pour en tenir compte.

Test et conception ... un seul et même

À mon avis, TDD considère simplement que le test fait partie intégrante du design plutôt que de le faire à la fin pour le valider. Au fur et à mesure que vous commencez à utiliser TDD, vous vous rendez compte de la manière dont vous détruisez / endommagez votre système lors de sa conception. Personnellement, je ne fais pas toujours mes tests en premier. Bien sûr, je fais les tests (unitaires) évidents sur une interface, mais les gains réels proviennent des tests d'intégration et de spécification que je crée lorsque je pense à une nouvelle façon créative de briser ce design. Dès que je pense à un moyen, je code un test et je vois ce qui se passe. Parfois, je peux vivre avec la conséquence, dans ce cas, je déplace le test dans un projet séparé qui ne fait pas partie de la construction principale (car il continuera d'échouer).

Alors qui conduit le spectacle?

Dans TDD, piloter ici signifie simplement que vos tests influencent tellement votre conception que l’on peut sentir qu’ils la pilotent réellement. Cependant, on en reste là, et je comprends vos préoccupations, c'est un peu effrayant ... Qui dirige la série?

VOUS conduisez, pas les tests. Les tests sont là pour que, à mesure que vous avancez, vous gagniez un bon niveau de confiance en ce que vous avez créé, vous permettant ainsi de continuer à construire en sachant que tout repose sur des bases solides.

solide tant que les tests sont solides

Exactement , d’où la conduite dans le TDD. Ce ne sont pas tant les tests qui déterminent tout le processus, mais ils auront une influence aussi profonde sur la façon dont vous faites les choses, sur la façon dont vous concevez et pensez votre système, que vous déléguerez une grande partie de votre processus de réflexion aux tests et en retour. ils auront une influence profonde sur votre conception.

oui mais si je fais ça avec mon pont th ....

arrêtez-vous là… l'ingénierie logicielle est TRÈS différente de toutes les autres pratiques d'ingénierie. En réalité, le génie logiciel a beaucoup plus de points communs avec la littérature. On peut prendre un livre fini, en extraire 4 chapitres et en écrire deux nouveaux pour les remplacer. Les coller dans le livre et vous avez toujours un bon livre. Avec de bons tests et de bons logiciels, vous pouvez extraire n’importe quelle partie de votre système et le remplacer par un autre. Le coût de ce processus n’est pas beaucoup plus élevé que ce qu’il était en train de créer. En fait, si vous avez effectué vos tests et que vous leur avez permis d’influencer suffisamment votre conception, il se peut qu’elle soit moins chère que de la créer, car vous aurez la certitude que ce remplacement ne brisera pas le contenu des tests.

Si c'est tellement bon, pourquoi ne fonctionne-t-il pas toujours?

Parce que les tests nécessitent un état d'esprit TRÈS différent de celui de la construction. Tous ne sont pas en mesure de revenir en arrière et, en fait, certaines personnes ne seront pas en mesure de construire des tests appropriés simplement parce qu'elles ne peuvent pas se donner la décision de détruire leur création. Cela donnera des projets avec trop peu de tests ou juste assez pour atteindre une métrique cible (la couverture de code nous vient à l’esprit). Ils accepteront volontiers les tests de trajectoire et les tests d'exception, mais oublieront les cas extrêmes et les conditions aux limites.

D'autres s'appuieront simplement sur des tests renonçant partiellement ou totalement à la conception. Chaque membre fait sa chose puis s'intègre à l'un l'autre. Le design est avant tout un outil de communication, nous posons des enjeux pour dire que c’est là que je serai, des croquis qui indiquent que c’est là que se trouveront les portes et les fenêtres. Sans cela, votre logiciel est condamné quel que soit le nombre de tests que vous avez effectués. L'intégration et les fusions seront toujours pénibles et ils manqueront de tests aux plus hauts niveaux d'abstractions.

Pour ces équipes, TDD pourrait ne pas être la solution.

Newtopien
la source
7

Avec TDD, vous n'avez pas tendance à écrire du code qui n'est pas facile ou rapide à tester. Cela peut sembler une petite chose, mais cela peut avoir un impact profond sur un projet car il est très difficile de refactoriser, de tester, de reproduire des bogues avec des tests et de vérifier les correctifs.

Il est également plus facile pour un nouveau développeur du projet de se mettre au diapason avec un meilleur code factorisé pris en charge par des tests.

Alb
la source
2
J'aime cela - cela souligne le fait que ce n'est pas tant le TDD qui crée les avantages (bien que les tests unitaires aient clairement une grande valeur) comme le type de code qu'il produit dans le sens où il est testable (de manière isolée) et toutes sortes de bonnes choses en découlent (séparation des préoccupations, IoC et injection de dépendance, etc., etc.)
Murph
1
@Murph ouais TDD vous aide à rester honnête :)
Alb
1
Pour être honnête, je ne suis pas réellement convaincu par l'argument "plus facile à maîtriser" - les tests peuvent être utiles, mais le code (dans son ensemble, pas nécessairement isolément) peut être un peu plus difficile à décoder, car certaines choses vont apparaissent comme par magie, par exemple, vous ne savez pas quelle implémentation de IInjectedThing vous utilisez.
Murph
@Murph La théorie est que l'implémentation IInjectedThing est également bien conçue et couverte par de bons tests, vous n'avez donc pas besoin de savoir ce que c'est de pouvoir comprendre une classe dans laquelle elle est injectée.
Adam Lear
@Anna - oui, jusqu'à un certain point ... si vous essayez de déterminer où quelque chose se brise (je pense toujours que la recherche d'insectes est un bon moyen de trouver son chemin dans un projet) ou lorsque quelque chose doit être changé / ajouté, vous devez savoir où. Même si cet endroit est bien encapsulé, vous devez toujours le trouver ... et si cela signifie remplacer quelque chose (nouvelle implémentation d'IWhatsit), vous devez savoir comment utiliser l'alternative implémentation. Encore une fois, je ne dis pas que la construction est mauvaise - trop de preuves du contraire - suggérant plutôt que certaines choses peuvent être moins évidentes.
Murph
5

J'y ai beaucoup réfléchi, même si je ne pratique pas beaucoup le TDD moi-même. Il semble exister une corrélation positive (forte?) Entre la qualité du code et le suivi de la mise à jour numérique.

1) Ma première idée est que, ce n’est (principalement) pas dû à TDD d’ajouter «meilleure qualité» au code (en tant que tel), c’est plutôt comme si TDD aidait à éliminer les pires habitudes et habitudes, et donc indirectement à améliorer la qualité.

Je dirais même que ce n'est pas le test en soi, mais le processus de rédaction de ces tests. Il est difficile d'écrire des tests pour un code incorrect, et vice versa. Et garder cela à l'arrière de la tête lors de la programmation élimine beaucoup de mauvais codes.

2) Un autre point de vue (cela devient philosophique) est de suivre les habitudes mentales du maître. Vous n’apprenez pas à devenir un maître en suivant ses "habitudes externes" (par exemple, une longue barbe est une bonne chose), vous devez apprendre ses façons de penser internes, ce qui est difficile. Et en quelque sorte, obligeant les programmeurs (novices) à suivre TDD, à rapprocher leurs façons de penser de celles du maître.

Maglob
la source
+1 Je pense que tu as réussi, Maglob. J'apprécie particulièrement votre explication selon laquelle "TDD aide à éliminer les pires parties et habitudes, [...] augmentant indirectement la qualité". Et l'analogie de la longue barbe est très bonne aussi.
CesarGon
vous n'écrivez pas de tests pour un code incorrect, mais vous écrivez un test, puis écrivez le code pour que le test réussisse.
Maglob, pour l'amour du côté plus pratique des choses, vous l'aurez mieux couvert. @ Thorbjørn, je pense que Maglob suivait de plus près le fait que si votre conception projetée est nulle, vos tests devront sûrement aspirer directement au niveau de succion que vous essayez de concrétiser et son odeur pourrie devrait retomber dans vos tests avant vous commencez même à écrire un code réel.
Filip Dupanović
3

L'approche "test d'écriture + refactorisation jusqu'au passage" est incroyablement anti-ingénierie.

Vous semblez avoir une idée fausse à la fois sur le refactoring et le TDD.

Le refactoring de code est le processus de modification du code source d'un programme informatique sans modification de son comportement fonctionnel externe afin d'améliorer certains attributs non fonctionnels du logiciel.

Ainsi, vous ne pouvez pas refactoriser le code tant qu'il n'est pas passé .

Et TDD, en particulier les tests unitaires (que je considère comme l’amélioration fondamentale, puisqu'un autre test me semble plutôt plausible), ne consiste pas à redéfinir un composant avant qu’il ne fonctionne. Il s'agit de concevoir un composant et de travailler sur la mise en œuvre jusqu'à ce que le composant fonctionne comme prévu.

En outre, il est important de bien comprendre que les tests unitaires consistent à tester des unités . En raison de la tendance à toujours écrire plein de choses à partir de zéro, il est important de tester de telles unités. Un ingénieur civil connaît déjà les spécifications des unités qu’il utilise (les différents matériaux) et peut s’attendre à ce qu’elles fonctionnent. Ce sont deux choses qui souvent ne s’appliquent pas aux ingénieurs en logiciel, et il est très ingénieux de tester les unités avant de les utiliser, car cela implique d’utiliser des composants testés et de haute qualité.
Si un ingénieur civil avait l’idée d’utiliser un nouveau tissu de fibres pour fabriquer un toit recouvrant un stade, vous devriez l’attendre à ce qu’il le teste en tant qu’unité, c’est-à-dire qu’il définisse les spécifications requises (par exemple poids, perméabilité, stabilité, etc.) et puis testez-le et affinez-le jusqu'à ce qu'il les rencontre.

C'est pourquoi TDD fonctionne. Parce que si vous construisez un logiciel avec des unités testées, les chances sont bien meilleures que cela fonctionne, si vous les connectez ensemble et si ce n’est pas le cas, vous pouvez vous attendre à ce que le problème se trouve dans votre code collé, en supposant que vos tests couvrent bien.

edit:
Refactoring signifie: pas de changement de fonctionnalité. Un des points de l’écriture du test unitaire est de s’assurer que le refactoring ne rompt pas le code. TDD est donc censé assurer que la refactorisation n’a pas d’effets secondaires.
La granularité n'est pas un sujet de perspective, car comme je l'ai dit, teste à l'unité les unités de test et non les systèmes, la granularité étant définie avec précision.

TDD encourage une bonne architecture. Cela vous oblige à définir et à mettre en œuvre les spécifications de toutes vos unités, ce qui vous oblige à les concevoir avant leur mise en œuvre, ce qui est tout le contraire de ce que vous semblez penser. TDD dicte la création d'unités, qui peuvent être testées individuellement et sont donc complètement découplées.
TDD ne signifie pas que je lance un test logiciel sur code spaghetti et agite les pâtes jusqu’à ce qu’elles passent.

Contrairement au génie civil, en génie logiciel, un projet évolue généralement en permanence. En génie civil, vous devez construire un pont en position A, pouvant transporter x tonnes et suffisamment large pour n véhicules par heure.
En génie logiciel, le client peut en principe décider à tout moment (éventuellement après l'achèvement des travaux) qu'il souhaite un pont à deux ponts et qu'il souhaite le connecter à l'autoroute la plus proche et qu'il souhaite qu'il s'agisse d'un pont levant, car son entreprise récemment commencé à utiliser des navires à voile.
Les ingénieurs en logiciel sont chargés de modifier les conceptions. Non pas parce que leurs conceptions sont défectueuses, mais parce que c'est le modus operandi. Si le logiciel est bien conçu, il peut être redessiné à un niveau élevé, sans avoir à réécrire tous les composants de bas niveau.

TDD consiste à concevoir un logiciel avec des composants hautement découplés testés individuellement. Bien exécuté, il vous aidera à répondre aux changements de besoins de manière significative, plus rapidement et plus sûrement que sans.

TDD ajoute des exigences au processus de développement, mais n'interdit aucune autre méthode d'assurance qualité. Certes, TDD n'offre pas la même sécurité que la vérification formelle, mais là encore, la vérification formelle est extrêmement coûteuse et impossible à utiliser au niveau du système. Et encore, si vous le vouliez, vous pourriez combiner les deux.

TDD englobe également des tests autres que les tests unitaires, effectués au niveau du système. Je trouve cela facile à expliquer mais difficile à exécuter et difficile à mesurer. En outre, ils sont tout à fait plausibles. Bien que je voie absolument leur nécessité, je ne les considère pas vraiment comme des idées.

En fin de compte, aucun outil ne résout réellement un problème. Les outils ne font que résoudre un problème plus facilement. Vous pouvez demander: Comment un ciseau m'aidera-t-il avec une belle architecture? Eh bien, si vous envisagez de faire des murs droits, les briques droites sont utiles. Et oui, d'accord, si vous donnez cet outil à un idiot, il le fera probablement claquer du pied, mais ce n'est pas la faute du burin, bien que ce ne soit pas un défaut de TDD de donner une fausse sécurité aux novices, qui n'écrit pas de bons tests.
En fin de compte, on peut dire que le TDD fonctionne beaucoup mieux que pas de TDD.

back2dos
la source
Je ne pense pas avoir une idée fausse; Je suis d'accord avec la définition de refactorisation de code que vous avez publiée, mais je pense également que vous devez examiner la granularité des modifications apportées au code. Lorsque vous parlez de "processus de modification du code source d'un programme informatique", vous devez comprendre que, du point de vue d'un certain ensemble, le comportement ne change pas, mais le comportement des parties change également. C'est comme ça que le changement est effectué. En plus de cela, je vous entends parler de la raison pour laquelle TDD fonctionne (et je la partage), mais comment l’architecture est-elle traitée comme dans mon message original?
CesarGon
@CesarGon: Poster mis à jour.
back2dos
2

Je n'aime pas que vous disiez «le test, plutôt que l'utilisateur, définit l'exigence». Je pense que vous envisagez uniquement les tests unitaires dans TDD, alors que cela couvre également les tests d'intégration.

En plus de tester les bibliothèques qui constituent la base du logiciel, écrivez les tests qui couvrent les interactions de vos utilisateurs avec le logiciel / le site Web / peu importe. Ceux-ci viennent directement des utilisateurs, et des bibliothèques comme concombre (http://cukes.info) peuvent même laisser vos utilisateurs écrire les tests eux-mêmes, en langage naturel.

TDD encourage également la flexibilité dans le code - si vous passez toujours du temps à concevoir l'architecture de quelque chose, il sera extrêmement difficile d'apporter ces modifications ultérieurement si nécessaire. Commencez par écrire quelques tests, puis écrivez un petit code qui passe ces tests. Ajoutez plus de tests, ajoutez plus de code. Si vous devez changer radicalement le code, vos tests sont toujours valables.

Et contrairement aux ponts et aux voitures, un seul logiciel peut subir d’énormes changements au cours de sa vie. Effectuer un refactoring complexe sans que les tests ne soient écrits en premier revient à poser des problèmes.

Sevenseacat
la source
Je vous entends parler des avantages que vous réclamez pour le TDD. Mais pour autant que je sache, vous n'abordez pas les problèmes d'architecture et de qualité des tests que je demande explicitement dans ma question.
CesarGon
@CesarGon: Je pense que vos questions spécifiques s'appliquent à tout type de test, pas seulement au TDD. Je me suis donc concentré sur les caractéristiques spécifiques du TDD qui «fonctionnent».
Sevenseacat
1
Les tests d'intégration ont certainement plus de sens que les tests unitaires autonomes. La plupart des bogues sur lesquels je suis tombé par hasard n'auraient jamais été découverts par des tests unitaires, mais uniquement en testant le système réel dans son ensemble, avec tous ses verrous et sifflets en place.
2

Je pense que vous abordez le premier point sous le mauvais angle.

D'un point de vue théorique, nous prouvons que quelque chose fonctionne en vérifiant les points d'échec. C'est la méthode utilisée. Il existe peut-être de nombreuses autres façons de prouver que quelque chose est fonctionnel, mais TDD s’est établi en raison de la simplicité de son approche par bits: si cela ne casse pas, cela fonctionne.

En pratique, cela se traduit de manière franche en: nous pouvons maintenant passer à la chose suivante (après avoir appliqué avec succès TDD pour satisfaire tous les prédicats). Si vous abordez TDD de ce point de vue, alors il ne s'agit pas "d'écrire des tests + un refactor avant de réussir" mais plutôt d' avoir terminé, je me concentre maintenant sur la fonctionnalité suivante, qui est désormais la chose la plus importante .

Pensez comment cela s'applique au génie civil. Nous construisons un stade pouvant accueillir un public de 150000 personnes. Après avoir prouvé que l'intégrité structurelle du stade est saine, nous avons d'abord satisfait la sécurité . Nous pouvons maintenant nous concentrer sur d'autres questions qui revêtent une importance immédiate, telles que les toilettes, les stands de nourriture, les sièges, etc.… rendant l'expérience du public plus agréable. Ceci est une simplification excessive, car TDD a beaucoup plus à offrir, mais le point crucial est que vous ne créez pas la meilleure expérience utilisateur possible si vous vous concentrez à la fois sur des fonctionnalités nouvelles et intéressantes et sur le maintien de l'intégrité en même temps. Vous l'obtenez à moitié dans les deux cas. Je veux dire, comment pouvez-vous savoir exactement commentbeaucoup de toilettes et où devriez-vous placer pour 150000 personnes? J'ai rarement vu des stades s'effondrer de ma vie, mais j'ai dû faire la queue à la mi-temps à de nombreuses occasions. Cela signifie que le problème des toilettes est sans doute plus complexe et que, si les ingénieurs consacraient moins de temps à la sécurité, ils pourraient enfin être en mesure de résoudre le problème des toilettes.

Votre deuxième point est dénué de pertinence, car nous avons déjà convenu que les absolus sont une entreprise idiote et que Hank Moody dit qu'ils n'existent pas (mais je n'arrive pas à trouver une référence pour cela).

Filip Dupanović
la source
+1 pour une bonne explication de mon premier point et pour la référence à Hank Moody. Glorieux.
CesarGon
2
Merci, j'apprécie. Je considère le TDD davantage comme un phénomène psychologique que comme une approche / un processus technique. Mais ce n'est que ma vision du monde sur le sujet.
Filip Dupanović le
Pouvez-vous savoir exactement combien de toilettes et où elles devraient être placées? La réponse est oui - allez demander à n'importe quel architecte et il vous dira que cette information est faite à l'avance et parfois avec des données statistiques claires pour la sauvegarder.
gbjbaanb
1

TDD en génie logiciel est une bonne pratique, au même titre que la gestion des erreurs dans les applications, ainsi que la journalisation et les diagnostics (bien que cela fasse partie de la gestion des erreurs).

TDD ne doit pas être utilisé comme un outil permettant de réduire le développement de logiciels au codage d'essai et d'erreur. Néanmoins, la plupart des programmeurs observent les journaux d’exécution, surveillent les exceptions dans le débogueur ou utilisent d’autres signes d’échec / de succès au cours de leur phase de développement consistant à coder / compiler / exécuter l’application - toute la journée.

TDD n’est qu’un moyen de formaliser et d’automatiser ces étapes pour vous rendre plus productif en tant que développeur.

1) Vous ne pouvez pas comparer l’ingénierie logicielle à la construction de ponts, la flexibilité de la construction des ponts n’est pas comparable à celle de la conception d’un logiciel. Construire le pont revient à écrire le même programme encore et encore dans une machine avec des pertes. Les ponts ne peuvent pas être dupliqués et réutilisés comme les logiciels. Chaque pont est unique et doit être fabriqué. La même chose vaut pour les voitures et autres conceptions.

La chose la plus difficile en génie logiciel est de reproduire les erreurs, quand un pont tombe en panne, il est généralement très facile de déterminer ce qui a mal tourné et, en théorie, il est facile de reproduire la panne. Lorsqu'un programme d'ordinateur échoue, il peut s'agir d'une chaîne d'événements complexe qui a entraîné le système dans un état défaillant et il peut être très difficile de déterminer où se trouve l'erreur. TDD et le test unitaire facilitent le test de la robustesse des composants logiciels, des bibliothèques et des algorithmes.

2) L'utilisation de tests unitaires faibles et de scénarios de test superficiels qui ne sollicitent pas le système pour créer un faux sentiment de confiance est simplement une mauvaise pratique. Ignorer la qualité architecturale d'un système et simplement remplir les tests est évidemment aussi mauvais. Mais tricher sur les lieux de la construction d'un gratte-ciel ou d'un pont pour économiser du matériel et ne pas suivre les plans est aussi grave et cela arrive tout le temps ...

Ernelli
la source
Je ne suis pas d'accord avec votre implication selon laquelle il est facile, dans les systèmes physiques (c'est-à-dire sans logiciel), de reproduire les défaillances. Regardez le travail extrêmement complexe et ardu nécessaire pour déterminer les causes profondes des défaillances mécaniques dans les accidents de la circulation aérienne, par exemple.
CesarGon
Hm, vous comparez maintenant un avion de ligne qui s'écrase à un pont défaillant, un pont ne pouvant généralement pas voler, le dossier étant fermé. Mais la comparaison entre avions et logiciels est parfois valable. Les deux domaines sont très complexes et nécessitent une méthodologie de test structurée. Ainsi, lorsqu'un pont tombe en panne, vous savez qu'il a été surchargé. Lorsqu'un avion se bloque, vous savez pertinemment que l'état anormal de voler au-dessus du sol a échoué, mais la raison nécessite généralement une enquête approfondie de la même manière qu'une défaillance logicielle.
Ernelli
Les ponts peuvent être dupliqués - ou au moins, le plan de pont que vous achetez chez l’architecte peut, en gros, être modifié en fonction de votre situation. Le fait est que si vous avez besoin d’un pont, vous irez chez l’architecte qui ne vous donnera qu’une liste de quelques types que vous pouvez avoir - suspension, caisse, arc, etc., ainsi qu’une liste limitée de matériaux de construction.
gbjbaanb
1

Si vous acceptez le fait que plus tôt les bogues sont trouvés, moins le coût de leur réparation est rentable, alors seul le TDD en vaut la peine.

SnoopDougieDoug
la source
1
Avez-vous des preuves que des bugs sont détectés plus tôt dans un environnement TDD? De plus, qu'en est-il des effets secondaires du TDD, tels que l'impact sur l'architecture?
CesarGon
0

TDD n'est pas vraiment une question de test. Et ce n'est certainement pas un remplacement pour de bons tests. Ce que cela vous donne est un design bien pensé, facile à consommer par le consommateur, facile à entretenir et à refactoriser ultérieurement. Ces éléments entraînent à leur tour moins de bogues et une conception de logiciel meilleure et plus adaptable. TDD vous aide également à réfléchir à vos hypothèses et à les documenter, en trouvant souvent que certaines d’entre elles étaient incorrectes. Vous les découvrez très tôt dans le processus.

Et comme avantage supplémentaire, vous disposez d'une grande suite de tests que vous pouvez exécuter pour vous assurer qu'un refactoring ne modifie pas le comportement (entrées et sorties) de votre logiciel.

Marcie
la source
6
-1. Beaucoup de gens continuent à dire cela, mais je n'ai pas encore vu la magie qui fait que cela se produise.
Bart van Ingen Schenau le
@Bart van Ingen Schenau, avez-vous suivi le TDD? Je le fais depuis environ 4 ans et j'ai vraiment vu la "magie" se produire.
Marcie
0

Je vais vous donner une réponse courte. En règle générale, TDD est considéré de manière erronée, tout comme le test unitaire. Je n'ai jamais compris les tests unitaires jusqu'à récemment, après avoir visionné une bonne vidéo de discussion technique. Essentiellement, TDD indique simplement que vous voulez que les choses suivantes fonctionnent. Ils DOIVENT être mis en œuvre. Ensuite, vous concevez le reste du logiciel comme vous le feriez normalement.

C'est un peu comme écrire des cas d'utilisation pour une bibliothèque avant de concevoir celle-ci. Sauf que vous pouvez changer le cas d'utilisation dans une bibliothèque et que vous ne pouvez pas le faire pour TDD (j'utilise TDD pour la conception d'API). Vous êtes également encouragé à ajouter plus de test et à penser aux entrées / utilisations sauvages que le test peut avoir. Je trouve cela utile lors de l'écriture de bibliothèques ou d'API où, si vous changez quelque chose, vous devez savoir que vous avez cassé quelque chose. Dans la plupart des logiciels quotidiens, je ne me dérange pas car pourquoi ai-je besoin d'un scénario de test pour un utilisateur appuyant sur un bouton ou si je veux accepter une liste CSV ou une liste avec une entrée par ligne ... Cela n'a pas d'importance, je suis autorisé pour le changer donc je ne devrais pas / ne peux pas utiliser TDD.


la source
0

Le logiciel est organique, quand l'ingénierie structurelle est en béton.

Lorsque vous construisez votre pont, il restera un pont et il est peu probable qu'il devienne autre chose dans un court laps de temps. Des améliorations seront apportées au fil des mois et des années, mais pas des heures et des jours comme dans les logiciels.

Lorsque vous testez isolément, vous pouvez utiliser deux types de framework. Cadre contraint et non contraint. Les frameworks sans contrainte (en .NET) vous permettent de tout tester et de tout substituer, quels que soient les modificateurs d'accès. C'est-à-dire que vous pouvez écraser et simuler des composants privés et protégés.

La plupart des projets que j'ai vus utilisent des cadres contraints (RhinoMocks, NSubstitute, Moq). Lorsque vous testez avec ces frameworks, vous devez concevoir votre application de manière à pouvoir injecter et substituer des dépendances au moment de l'exécution. Cela implique que vous devez avoir une conception faiblement couplée. Une conception faiblement couplée (si elle est bien faite) implique une meilleure séparation des préoccupations, ce qui est une bonne chose.

En résumé, j’estime que si votre conception est testable, elle est donc faiblement couplée et les problèmes sont bien séparés.

En passant, j'ai vu des applications vraiment testables, mais mal écrites du point de vue de la conception orientée objet.

CodeART
la source
0

Pourquoi TDD fonctionne-t-il?

Ce n'est pas.

Précision: les tests automatisés valent mieux que pas de tests. Cependant, je pense personnellement que la plupart des tests unitaires sont des déchets, car ils sont généralement tautologiques (c’est-à-dire qu’ils ressortent clairement du code à tester) et qu’il est difficile de prouver qu’ils sont cohérents, non redondants et couvrent tous les cas de frontière (où des erreurs se produisent habituellement). ).

Et le plus important: une bonne conception logicielle ne tombe pas comme par magie dans les tests, car elle est annoncée par de nombreux évangélistes agiles / TDD. Toute personne affirmant le contraire fournira des liens vers des recherches scientifiques examinées par des pairs qui le prouvent, ou tout au moins une référence à un projet open source où les avantages du TDD peuvent être potentiellement étudiés par l'historique de ses modifications de code.

KolA
la source