Quand écrivez-vous le "vrai" code dans TDD?

johnny 08/19/2017. 11 answers, 20.464 views
tdd

Tous les exemples que j'ai lus et lus sur des vidéos de formation ont des exemples simplistes. Mais ce que je ne vois pas si je fais le "vrai" code après que je devienne vert. Est-ce la partie "Refactor"?

Si j'ai un objet assez complexe avec une méthode complexe, et j'écris mon test et le strict minimum pour le faire passer (après le premier échec, Red). Quand est-ce que je reviens et écris le vrai code? Et combien de code réel puis-je écrire avant de retester? Je devine que le dernier est plus d'intuition.

Edit: Merci à tous ceux qui ont répondu. Toutes vos réponses m'ont énormément aidé. Il semble y avoir différentes idées sur ce que je demandais ou confus, et peut-être qu'il y en a, mais ce que je demandais, c'est que j'ai une demande de construction d'école.

Dans mon design, j'ai une architecture avec laquelle je veux commencer, User Stories, etc. De là, je prends ces User Stories, et je crée un test pour tester l'User Story. L'utilisateur dit, nous avons des gens inscrits à l'école et payer les frais d'inscription. Donc, je pense à un moyen de faire échouer. Ce faisant, je conçois une classe de test pour la classe X (peut-être Student), qui échouera. Je crée ensuite la classe "Étudiant". Peut-être "école" je ne sais pas.

Mais, en tout cas, le Design TD me force à réfléchir à l'histoire. Si je peux faire échouer un test, je sais pourquoi il échoue, mais cela suppose que je puisse le faire passer. Il s'agit de la conception.

Je compare cela à penser à la récursivité. La récursivité n'est pas un concept difficile. Il peut être plus difficile d'en garder la trace dans votre tête, mais en réalité, la partie la plus difficile est de savoir quand la récursion «se casse», quand arrêter (mon opinion, bien sûr). Donc je dois penser à ce qui s'arrête la récursivité en premier. Ce n'est qu'une analogie imparfaite, et il suppose que chaque itération récursive est un «passage». Encore une fois, juste une opinion.

Dans la mise en œuvre, l'école est plus difficile à voir. Les livres comptables et bancaires sont «faciles» dans le sens où vous pouvez utiliser l'arithmétique simple. Je peux voir a + b et retourner 0, etc. Dans le cas d'un système de personnes, je dois réfléchir plus à la façon de implement en implement cela. J'ai le concept de l'échec, passer, refactor (principalement à cause de l'étude et de cette question.)

Ce que je ne sais pas est basé sur le manque d'expérience, à mon avis. Je ne sais pas comment échouer à l'inscription d'un nouvel étudiant. Je ne sais pas comment faire échouer quelqu'un qui tape un nom de famille et qui est enregistré dans une base de données. Je sais comment faire un + 1 pour les mathématiques simples, mais avec des entités comme une personne, je ne sais pas si je ne fais que tester si je récupère une ID de base de données ou autre chose quand quelqu'un entre un nom dans un base de données ou les deux ou aucun.

Ou, peut-être cela montre que je suis toujours confus.

5 Comments
187 hobbs 07/25/2017
Après le TDD, les gens rentrent chez eux pour la nuit.
14 Goyo 07/25/2017
Pourquoi pensez-vous que le code que vous avez écrit n'est pas réel?
2 johnny 07/26/2017
@RubberDuck Plus que les autres réponses ont fait. Je suis sûr que je vais y revenir bientôt. C'est encore un peu étranger, mais je ne vais pas abandonner. Ce que vous avez dit était logique. J'essaie juste de le rendre sensé dans mon contexte ou une application d'affaires régulière. Peut-être un système d'inventaire ou similaire. Je dois le considérer. Je suis reconnaissant pour votre temps cependant. Merci.
1 Edmund Reed 07/26/2017
Les réponses sont déjà au rendez-vous, mais tant que tous vos tests sont passés, et que vous n'avez pas besoin de nouveaux tests / fonctionnalités, on peut supposer que le code que vous avez est fini, le pelage des barres.
3 Borjab 07/26/2017
Il y a une hypothèse dans la question qui peut être problématique dans "J'ai un objet assez complexe avec une méthode complexe". Dans TDD, vous devez d'abord écrire vos tests pour commencer avec un code assez simple. Cela vous obligera à coder une structure conviviale qui devra être modulaire. Un comportement si complexe sera créé en combinant des objets plus simples. Si vous finissez avec un objet ou une méthode assez complexe, c'est quand vous refactorisez

11 Answers


RubberDuck 07/27/2017.

Si j'ai un objet assez complexe avec une méthode complexe, et j'écris mon test et le strict minimum pour le faire passer (après le premier échec, Red). Quand est-ce que je reviens et écris le vrai code? Et combien de code réel puis-je écrire avant de retester? Je devine que le dernier est plus d'intuition.

Vous ne "retournez" pas et écrivez "code réel". Tout est du vrai code. Ce que vous faites est de revenir en arrière et d'ajouter un autre test qui vous forces à change votre code afin de faire passer le nouveau test.

Pour combien de code écrivez-vous avant de refaire le test? Aucun. Vous écrivez zero code sans un test qui échoue qui vous forces à écrire plus de code.

Remarquez le motif?

Passons à travers un autre exemple simple dans l'espoir que ça aide.

 Assert.Equal("1", FizzBuzz(1)); 

Facile peazy.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

Pas ce que vous appelez du vrai code, n'est-ce pas? Ajoutons un test qui force un changement.

 Assert.Equal("2", FizzBuzz(2)); 

Nous pourrions faire quelque chose de stupide comme if n == 1 , mais nous passerons à la solution saine.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Cool. Cela fonctionnera pour tous les numéros non-FizzBuzz. Quelle est la prochaine entrée qui forcera le code de production à changer?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

Et encore. Ecrivez un test qui ne passera pas encore.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

Et nous avons maintenant couvert tous les multiples de trois (qui ne sont pas aussi des multiples de cinq, nous le noterons et reviendrons).

Nous n'avons pas encore écrit de test pour "Buzz", alors écrivons ça.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

Et encore une fois, nous savons qu'il y a un autre cas que nous devons gérer.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

Et maintenant nous pouvons gérer tous les multiples de 5 qui ne sont pas aussi multiples de 3.

Jusqu'à présent, nous avons ignoré l'étape de refactoring, mais je vois une duplication. Nettoyons ça maintenant.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Cool. Maintenant, nous avons supprimé la duplication et créé une fonction bien nommée. Quel est le prochain test que nous pouvons écrire qui va nous forcer à changer le code? Bien, nous avons évité le cas où le nombre est divisible par 3 et 5. Écrivons maintenant.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Les tests passent, mais nous avons plus de duplication. Nous avons des options, mais je vais appliquer "Extraire la variable locale" plusieurs fois pour que nous refactorions au lieu de réécrire.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Et nous avons couvert tous les commentaires raisonnables, mais qu'en est-il unreasonable commentaires unreasonable ? Que se passe-t-il si nous passons 0 ou un résultat négatif? Ecrivez ces cas de test.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Est-ce que ça commence à ressembler à du "vrai code"? Plus important encore, à quel moment a-t-il cessé d'être un «code irréel» et de devenir «réel»? C'est quelque chose à méditer ...

Donc, j'ai été capable de le faire simplement en cherchant un test que je savais ne pas réussir à chaque étape, mais j'ai eu beaucoup de pratique. Quand je suis au travail, les choses ne sont jamais aussi simples et je ne sais pas toujours quel test forcera un changement. Parfois je vais écrire un test et être surpris de voir que ça passe déjà! Je recommande fortement que vous preniez l'habitude de créer une "liste de test" avant de commencer. Cette liste de tests doit contenir toutes les entrées "intéressantes" auxquelles vous pouvez penser. Vous pourriez ne pas les utiliser tous et vous ajouterez probablement des cas au fur et à mesure, mais cette liste sert de feuille de route. Ma liste de tests pour FizzBuzz ressemblerait à ceci.

  • Négatif
  • Zéro
  • Un
  • Deux
  • Trois
  • Quatre
  • Cinq
  • Six (multiple non trivial de 3)
  • Neuf (3 au carré)
  • Dix (multiple non trivial de 5)
  • 15 (multiple de 3 et 5)
  • 30 (multiple non trivial de 3 et 5)
5 comments
3 maple_shaft♦ 07/27/2017
Les commentaires ne sont pas pour une discussion prolongée; cette conversation a été déplacée pour discuter .
40 GManNickG 07/27/2017
À moins que je ne comprenne complètement cette réponse: «Nous pourrions faire quelque chose de stupide comme si n == 1, mais nous passerons à la solution saine. - Tout était stupide. Si vous savez d'avance vous voulez une fonction qui fait <spec>, écrivez des tests pour <spec> et passez la partie où vous écrivez des versions qui échouent évidemment <spec>. Si vous trouvez un bug dans <spec> alors assurez-vous: d'abord écrire un test pour vérifier que vous pouvez l'exercer avant le correctif et observer le test qui passe après le correctif. Mais il n'est pas nécessaire de simuler toutes ces étapes intermédiaires.
15 user3791372 07/28/2017
Les commentaires qui soulignent les failles majeures dans cette réponse et TDD en général ont été déplacés pour discuter. Si vous envisagez d'utiliser TDD, veuillez lire le "chat". Malheureusement, les commentaires "qualité" sont maintenant cachés parmi une charge de discussion pour les futurs étudiants à lire.
nbro 07/28/2017
Je serais plus précis quant au contenu de cette "liste de test", si vous vouliez améliorer cette réponse. Je parlerais explicitement de "valeurs limites" et de "partitionnement de classes".
2 hvd 07/30/2017
@GManNickG Je crois que le but est d'obtenir la bonne quantité de tests. En écrivant les tests au préalable, il est facile de passer à côté des cas particuliers qui doivent être testés, ce qui conduit à des situations qui ne sont pas couvertes de manière adéquate dans les tests ou à la même situation. Si vous pouvez le faire sans ces étapes intermédiaires, génial! Cependant, tout le monde ne peut pas le faire, c'est quelque chose qui demande de la pratique.

GenericJon 07/24/2017.

Le code "réel" est le code que vous écrivez pour effectuer votre test. Really . C'est si simple.

Quand les gens parlent d'écrire le strict minimum pour rendre le test vert, cela signifie simplement que votre vrai code devrait suivre le principe de YAGNI .

L'idée de l'étape du refactor est simplement de nettoyer ce que vous avez écrit une fois que vous êtes satisfait qu'il répond aux exigences.

Tant que les tests que vous écrivez couvrent réellement vos besoins en produits, une fois qu'ils passent, le code est complet. Pensez-y, si toutes les exigences de votre entreprise ont un test et que tous ces tests sont verts, que pouvez-vous écrire de plus? (D'accord, dans la vraie vie, nous n'avons pas tendance à avoir une couverture de test complète, mais la théorie est solide.)

5 comments
44 Derek Elkins 07/24/2017
Les tests unitaires ne peuvent pas réellement englober les exigences de votre produit pour des exigences même relativement insignifiantes. Au mieux, ils échantillonnent l'espace d'entrée-sortie et l'idée est de généraliser (correctement) à l'espace d'entrée-sortie complet. Bien sûr, votre code pourrait être un gros switch avec un cas pour chaque test unitaire qui passerait tous les tests et échouerait pour toutes les autres entrées.
8 Taemyr 07/25/2017
@DerekElkins TDD mandat échoue aux tests. Ne pas échouer aux tests unitaires.
6 jonrsharpe 07/25/2017
@DerekElkins c'est pourquoi vous n'écrivez pas seulement des tests unitaires, et aussi pourquoi il y a une supposition générale que vous essayez de faire quelque chose et non pas de simuler!
35 Derek Elkins 07/25/2017
@jonrsharpe Par cette logique, je n'écrirais jamais des implémentations triviales. Par exemple, dans l'exemple de FizzBuzz dans la réponse de RubberDuck (qui n'utilise que des tests unitaires), la première implémentation est clairement "juste fausse". Ma compréhension de la question est exactement cette dichotomie entre l'écriture du code que vous connaissez est incomplète et le code que vous croyez sincèrement mettre en œuvre l'exigence, le «vrai code». Mon «gros switch » était conçu comme l'extrême logique de «rédiger le strict minimum pour rendre les tests verts». Je vois la question du PO comme étant: où TDD est le principe qui évite ce gros switch ?
2 Luaan 07/25/2017
@GenericJon C'est un peu trop optimiste dans mon expérience :) D'une part, il y a des gens qui aiment le travail répétitif aveugle. Ils seront plus heureux avec une déclaration de changement géant qu'avec une «prise de décision compliquée». Et pour perdre leur travail, ils auraient soit besoin de quelqu'un qui les appelle sur la technique (et ils ont de meilleures preuves qu'il perd réellement les opportunités / l'argent de l'entreprise!), Ou font exceptionnellement mal. Après avoir pris en charge la maintenance de nombreux projets de ce type, je peux dire qu'il est facile pour un code très naïf de durer des dizaines d'années, tant qu'il rend le client heureux (et payant).

Carl Raymond 07/24/2017.

La réponse courte est que le "code réel" est le code qui fait passer le test. Si vous pouvez faire passer votre test avec autre chose que du code réel, ajoutez d'autres tests!

Je suis d'accord que beaucoup de tutoriels sur TDD sont simplistes. Cela marche contre eux. Un test trop simple pour une méthode qui, disons, calcule 3 + 8 n'a vraiment pas d'autre choix que de calculer aussi 3 + 8 et de comparer le résultat. Cela donne l'impression que vous dupliquerez tout le code, et que le test ne sert à rien, un travail supplémentaire sujet aux erreurs.

Lorsque vous faites du bon test, cela vous indique comment structurer votre application et comment vous écrivez votre code. Si vous éprouvez de la difficulté à trouver des tests utiles et utiles, vous devriez probablement repenser votre conception. Un système bien conçu est facile à tester, ce qui signifie que les tests sensibles sont faciles à concevoir et à mettre en œuvre.

Lorsque vous écrivez vos tests en premier, regardez-les échouer, puis écrivez le code qui les fait passer, c'est une discipline pour vous assurer que tout votre code a des tests correspondants. Je ne suis pas servilement cette règle quand je code; souvent j'écris des tests après le fait. Mais faire des tests aide d'abord à rester honnête. Avec un peu d'expérience, vous commencerez à remarquer lorsque vous vous codez dans un coin, même si vous n'écrivez pas les tests en premier.

4 comments
6 Steve Jessop 07/26/2017
Personnellement, le test que j'écrirais serait assertEqual(plus(3,8), 11) , et non assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . Pour les cas plus complexes, vous recherchez toujours un moyen de prouver le résultat correct, other than de calculer dynamiquement le résultat correct dans le test et de vérifier l'égalité.
Steve Jessop 07/26/2017
Donc, pour une façon vraiment idiote de le faire pour cet exemple, vous pourriez prouver que plus(3,8) a retourné le bon résultat en en soustrayant 3, en soustrayant 8 de cela, et en vérifiant le résultat par rapport à 0. C'est évidemment équivalent à assertEqual(plus(3,8), 3+8) pour être un peu absurde, mais si le code testé est en train de construire quelque chose de plus compliqué qu'un simple entier, alors prendre le résultat et vérifier chaque partie la bonne approche. Alternativement, quelque chose comme for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 07/26/2017
... car cela évite la grande peur, qui est que lors de l'écriture du test, nous ferons la même erreur sur le sujet de "comment ajouter 10" que nous avons fait dans le code en direct. Donc le test évite soigneusement d'écrire n'importe quel code qui ajoute 10 à n'importe quoi, dans le test que plus() peut ajouter 10 à des choses. Nous comptons toujours sur les valeurs de boucle intial vérifiées par le programmeur, bien sûr.
3 Warbo 07/28/2017
Je tiens juste à souligner que même si vous écrivez des tests après le fait, c'est toujours une bonne idée de les voir échouer; trouver une partie du code qui semble crucial pour tout ce sur quoi vous travaillez, le modifier un peu (par exemple remplacer un + par un -, ou autre), lancer les tests et les voir échouer, annuler le changement et les regarder passer. Plusieurs fois j'ai fait cela le test n'échoue pas vraiment, ce qui le rend pire qu'inutile: non seulement il ne teste rien, il me donne une fausse confiance que quelque chose est testé!

Victor Cejudo 07/25/2017.

Parfois, certains exemples de TDD peuvent être trompeurs. Comme d'autres personnes l'ont déjà signalé, le code que vous écrivez pour faire passer les tests est le vrai code.

Mais ne pensez pas que le vrai code semble magique - c'est faux. Vous avez besoin d'une meilleure compréhension de ce que vous voulez accomplir et ensuite vous devez choisir le test en conséquence, en commençant par les cas les plus simples et les cas les plus simples.

Par exemple, si vous devez écrire un lexer, vous commencez avec une chaîne vide, puis avec un tas d'espaces, puis un nombre, puis un nombre entouré d'espaces, puis un mauvais numéro, etc. Ces petites transformations vous conduiront à le bon algorithme, mais vous ne sautez pas du cas le plus facile à un cas très complexe choisi bêtement pour obtenir le vrai code.

Bob Martin l'explique parfaitement ici .


CandiedOrange 07/25/2017.

La partie refactor est nettoyée quand vous êtes fatigué et que vous voulez rentrer à la maison.

Lorsque vous êtes sur le point d'ajouter une fonctionnalité, la partie refactor est ce que vous modifiez avant le test suivant. Vous refactorisez le code pour faire de la place pour la nouvelle fonctionnalité. Vous faites cela quand vous know ce que cette nouvelle fonctionnalité sera. Pas quand vous l'imaginez.

Cela peut être aussi simple que de renommer GreetImpl en GreetWorld avant de créer une classe GreetMom (après avoir ajouté un test) pour ajouter une fonctionnalité qui affichera "Hi Mom".


graeme 07/27/2017.

Mais le vrai code apparaîtrait dans l'étape refactor de la phase TDD. C'est à dire le code qui devrait faire partie de la version finale.

Les tests doivent être effectués chaque fois que vous effectuez un changement.

La devise du cycle de vie TDD serait: RÉFRACTEUR VERT ROUGE

RED : Écris les tests

GREEN : Faites une tentative honnête pour obtenir le code fonctionnel qui réussit les tests le plus rapidement possible: code en double, obscurément nommé hacks de variables de l'ordre le plus élevé, etc.

REFACTOR : Nettoyer le code, nommer correctement les variables. SECHE le code.

5 comments
5 mcottle 07/25/2017
Je sais ce que vous dites à propos de la phase "verte" mais cela implique que les valeurs de retour du câblage pour faire passer les tests soient appropriées. Dans mon expérience "Green" devrait être une tentative honnête pour rendre le code de travail pour répondre à l'exigence, il peut ne pas être parfait mais il devrait être aussi complet et "expédiable" que le développeur peut gérer dans un premier passage. Le refactoring est probablement mieux fait quelque temps plus tard, après que vous ayez fait plus de développement et que les problèmes avec le premier passage deviennent plus apparents et que les opportunités de DRY émergent.
graeme 07/25/2017
@mcottle je considère que tous ces éléments font partie de la même tâche. faites-le, puis nettoyez-le. D'autres refactorings devraient avoir lieu au fil du temps dans le cadre d'autres tâches.
1 Bryan Boettcher 07/25/2017
@mcottle: vous pourriez être surpris du nombre d'implémentations d'un référentiel get-only qui peuvent être des valeurs codées en dur dans le codebase. :)
6 Kaz 07/25/2017
Pourquoi est-ce que j'écrirais du code de merde et le nettoierais, quand je pourrais produire un code de qualité de production presque aussi rapide que je peux taper? :)
1 Kaz 07/27/2017
@ TimothyTruckle Qu'est-ce que cela prend 50 minutes pour trouver le changement le plus simple possible, mais seulement 5 pour trouver le deuxième changement le plus simple possible? Allons-nous avec le deuxième plus simple ou continuer à chercher le plus simple?

Timothy Truckle 07/27/2017.

Quand écrivez-vous le "vrai" code dans TDD?

La phase red est l'endroit où vous write code.

Dans la phase de refactoring , l'objectif principal est de delete code.

En phase red , vous faites tout pour que le test passe as quick as possible et at any cost . Vous ignorez complètement ce que vous avez déjà entendu parler de bonnes pratiques de codage ou de modèle de conception. Rendre le test vert est tout ce qui compte.

Dans la phase de refactoring , vous nettoyez le désordre que vous venez de faire. Maintenant vous regardez d'abord si la modification que vous venez de faire est le type le plus haut de la liste Priorité de la transformation et s'il y a une duplication de code, vous pouvez le supprimer en appliquant un motif de conception.

Enfin, vous améliorez la lisibilité en renommant les identifiants et en extrayant magic numbers et / ou les chaînes littérales aux constantes.


Ce n'est pas un refactor rouge, c'est un refactor rouge-vert. - Rob Kinyon

Merci d'avoir signalé cela.

C'est donc la phase green où vous écrivez le real code

Dans la phase red , vous écrivez la executable specification ...

2 comments
Rob Kinyon 07/27/2017
Ce n'est pas un refactor rouge, c'est un refactor rouge-vert. Le "rouge" est que vous prenez votre suite de tests du vert (tous les tests passent) au rouge (un test échoue). Le "vert" est l'endroit où vous prenez maladroitement votre suite de tests de rouge (un test échoue) à vert (tous les tests passent). Le "refactor" est l'endroit où vous prenez votre code et le rendre joli tout en laissant passer tous les tests.
Timothy Truckle 07/27/2017
@RobKinyon Merci, mis à jour la réponse.

Robert Andrzejuk 07/27/2017.

Vous écrivez Real Code tout le temps.

A chaque étape Vous écrivez du code pour satisfaire les conditions que Votre code satisfera pour les futurs appelants de Votre code (qui pourrait être Vous ou non ...).

Vous pensez que vous n'écrivez pas de code ( real ) utile, car vous pourriez le refactoriser dans un instant.

Le refactoring de code est le processus de restructuration du code informatique existant - modifiant l'affacturage - sans modifier son comportement externe.

Cela signifie que même si vous modifiez le code, les conditions que le code satisfait sont laissées inchangées. Et les contrôles que vous avez mis en œuvre pour vérifier votre code sont déjà là pour vérifier si vos modifications ont changé quelque chose. Donc, le code que vous avez écrit tout le temps est là, juste d'une manière différente.

Une autre raison Vous pourriez penser que ce n'est pas du vrai code, c'est que vous faites des exemples où le programme de fin peut déjà être prévu par vous. C'est très bien, car cela montre que vous avez des connaissances sur le domain vous programmez.
Mais souvent, les programmeurs sont dans un domain qui est new , unknown pour eux. Ils ne savent pas quel sera le résultat final et TDD est une technique pour écrire des programmes étape par étape, documentant nos knowledge sur la façon dont ce système devrait fonctionner et vérifiant que notre code fonctionne de cette façon.

Quand j'ai lu The Book (*) sur TDD, pour moi la caractéristique la plus importante qui s'est démarquée était la liste: TODO. Cela m'a montré que TDD est aussi une technique pour aider les développeurs à se concentrer sur une chose à la fois. Donc, c'est aussi une réponse à votre question ci-dessus How much Real code to write ? Je dirais assez de code pour se concentrer sur une chose à la fois.

(*) "Test Driven Development: By Example" par Kent Beck

1 comments
2 Robert Andrzejuk 07/27/2017
"Test Driven Development: By Example" par Kent Beck

Zenilogix 07/31/2017.

Vous n'écrivez pas de code pour faire échouer vos tests.

Vous écrivez vos tests pour définir ce que le succès devrait ressembler, ce qui devrait tous échouer au début parce que vous n'avez pas encore écrit le code qui passera.

L'idée d'écrire des tests qui échouent au début est de faire deux choses:

  1. Couvrez tous les cas - tous les cas nominaux, tous les cas de bord, etc.
  2. Validez vos tests. Si vous ne les voyez que passer, comment pouvez-vous être sûr qu'ils signaleront un échec de manière fiable quand il y en a un?

Le point derrière refactor-red-green est que d'écrire les tests corrects vous donne d'abord la confiance de savoir que le code que vous avez écrit pour réussir les tests est correct, et vous permet de refactoriser avec la confiance que vos tests vous informeront dès que quelque chose se brise, alors vous pouvez immédiatement revenir en arrière et réparer.

Dans ma propre expérience (C # / .NET), le test pur-first est un peu un idéal inaccessible, parce que vous ne pouvez pas compiler un appel à une méthode qui n'existe pas encore. Donc, "tester d'abord", c'est vraiment coder les interfaces et les implémentations de stubbing en premier, puis écrire les tests contre les stubs (qui échoueront initialement) jusqu'à ce que les stubs soient correctement étoffés. Je n'écris jamais de "code défaillant", juste en construisant des stubs.


Zan Lynx 07/27/2017.

Je pense que vous pouvez être confus entre les tests unitaires et les tests d'intégration. Je crois qu'il peut aussi y avoir des tests d'acceptation, mais cela dépend de votre processus.

Une fois que vous avez testé toutes les petites "unités", vous les testez toutes assemblées, ou "intégrées". C'est généralement un programme entier ou une bibliothèque.

Dans le code que j'ai écrit, l'intégration teste une bibliothèque avec divers programmes de test qui lisent les données et les transmettent à la bibliothèque, puis vérifient les résultats. Ensuite, je le fais avec des fils. Puis je le fais avec des fils et une fourchette () au milieu. Puis je l'exécute et tue -9 après 2 secondes, puis je le lance et vérifie son mode de récupération. Je le fuzz. Je le torture de toutes sortes de façons.

Tout cela est également testé, mais je n'ai pas un joli affichage rouge / vert pour les résultats. Il réussit, ou je creuse à travers quelques milliers de lignes de code d'erreur pour savoir pourquoi.

C'est là que vous testez le "vrai code".

Et j'ai juste pensé à cela, mais peut-être que vous ne savez pas quand vous êtes censé avoir fini d'écrire des tests unitaires. Vous avez fini d'écrire des tests unitaires lorsque vos tests exercent tout ce que vous avez spécifié. Parfois, vous pouvez perdre la trace de cela parmi tous les cas de gestion d'erreurs et de bords, donc vous pourriez vouloir faire un bon groupe de tests de chemin heureux qui vont simplement dans les spécifications.

1 comments
Peter Mortensen 07/27/2017
(c'est = possessif, c'est = "c'est" ou "c'est" Voir par exemple How to Use Its and It's .)

user3791372 07/27/2017.

En réponse au titre de la question: "Quand écrivez-vous le" vrai "code dans TDD?", La réponse est: "presque jamais" ou "très lentement".

Vous ressemblez à un étudiant, alors je vais répondre comme si je conseillais un étudiant.

Vous allez apprendre beaucoup de «théories» et de «techniques» de codage. Ils sont parfaits pour passer le temps sur des cours d'étudiant hors de prix, mais de très peu d'avantages pour vous que vous ne pourriez pas lire dans un livre dans la moitié du temps.

Le travail d'un codeur est uniquement de produire du code. Code qui fonctionne vraiment bien. C'est pourquoi vous, le codeur, planifie le code dans votre esprit, sur papier, dans une application appropriée, etc., et vous envisagez de contourner à l'avance les failles / trous possibles en pensant logiquement et latéralement avant de coder.

Mais vous devez savoir comment casser votre application pour être capable de concevoir du code décent. Par exemple, si vous ne connaissiez pas Little Bobby Table (xkcd 327), vous ne devriez probablement pas nettoyer vos entrées avant de travailler avec la base de données, vous ne pourrez donc pas sécuriser vos données autour de ce concept.

TDD est juste un workflow conçu pour minimiser les bugs dans votre code en créant les tests de ce qui pourrait mal se passer avant de coder votre application car le code peut devenir exponentiellement difficile plus vous introduisez de code et oubliez les bugs que vous pensiez. Une fois que vous pensez que vous avez terminé votre application, vous exécutez les tests et boom, espérons que les bugs sont attrapés avec vos tests.

TDD n'est pas - comme certains le croient - écrire un test, le faire passer avec un minimum de code, écrire un autre test, le passer avec un minimum de code, etc. Au contraire, c'est un moyen de vous aider à coder avec confiance. Cet idéal de refactorisation continue du code pour le faire fonctionner avec des tests est idiot, mais c'est un concept sympa chez les étudiants car cela les fait se sentir bien quand ils ajoutent une nouvelle fonctionnalité et qu'ils apprennent toujours à coder ...

S'il vous plaît ne pas tomber dans ce piège et voir votre rôle de codage pour ce qu'il est - le travail d'un codeur est uniquement de produire du code. Code qui fonctionne vraiment bien. Maintenant, rappelez-vous que vous serez sur l'horloge en tant que codeur professionnel, et votre client ne se souciera pas si vous avez écrit 100 000 assertions, ou 0. Ils veulent juste du code qui fonctionne. Vraiment bien, en fait.

5 comments
3 johnny 07/25/2017
Je ne suis même pas proche d'un étudiant, mais je lis et essaie d'appliquer de bonnes techniques et d'être professionnel. Donc en ce sens, je suis un "étudiant". Je pose simplement des questions très élémentaires parce que c'est comme ça que je suis. J'aime savoir exactement pourquoi je fais ce que je fais. Le cœur du problème. Si je ne comprends pas, je n'aime pas ça et je commence à poser des questions. J'ai besoin de savoir pourquoi, si je vais l'utiliser. TDD semble intuitivement bon à certains égards, comme savoir ce que vous devez créer et réfléchir, mais la mise en œuvre était difficile à comprendre. Je pense que j'ai une meilleure compréhension maintenant.
4 Sean Burton 07/27/2017
Ce sont les règles de TDD. Vous êtes libre d'écrire le code comme vous voulez, mais si vous ne suivez pas ces trois règles, vous ne faites pas de TDD.
2 user3791372 07/27/2017
"Règles" d'une personne? TDD est une suggestion pour vous aider à coder, pas une religion. C'est triste de voir tant de gens adhérer à une idée si anale. Même l'origine de TDD est controversée.
2 Alex 07/28/2017
@ user3791372 TDD est un processus très strict et clairement défini. Même si beaucoup pensent que cela signifie simplement «Faites des tests quand vous programmez», ce n'est pas le cas. Essayons de ne pas confondre les termes ici, cette question concerne le processus TDD, pas les tests généraux.

Related questions

Hot questions

Language

Popular Tags