[JAVA] Résumé de la formation TDD

C'est ABAB ↑ ↓ BA. Cet article n'a presque pas de composant Elm. Dans cet article, j'aimerais parler de la formation TDD (développement piloté par les tests) que je suis ** hebdomadaire ** dans le mystérieux groupe Zenelo, uniquement les bases du cycle TDD et les baby steps.

Cycle TDD et étape bébé

Tout d'abord, parlons de la prémisse du développement piloté par les tests. Dans le développement piloté par les tests, nous procéderons au développement tout en passant par le cycle suivant.

Red -> Green -> Refactor

Red

Vous écrirez le test qui échoue en premier. Qu'est-ce que cela signifie?

Pour le code d'implémentation, implémentez ** l'interface ** (l'implémentation est vide, mais le type est clairement défini et peut être appelé à partir du test). Cela ne devrait pas être une erreur de compilation.

class FizzBuzz {
    public static String fizzbuzz(int num) {
       return null;
    }
}

Ensuite, écrivez le code de test. Cela équivaut à ** concevoir et définir les exigences **. À ce stade, le code de test ne doit jamais être écrit selon l'implémentation **. ** **

public class FizzBuzzTest {
    @Test
public void Le numéro 3 est pétillant() {
        assertThat(FizzBuzz.fizzbuzz(3), is("fizz"));
    }
}

Le test échouera bien sûr. L'important ici est que ** Red ** indique ce qu'il faut mettre en œuvre ensuite et devient un ** design vivant **.

FizzBuzzTest >Le numéro 3 est Fizz FAILED
    java.lang.AssertionError:
    Expected: is "fizz"
         but: was null
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.junit.Assert.assertThat(Assert.java:956)
        at org.junit.Assert.assertThat(Assert.java:923)
        at FizzBuzzTest.Le numéro 3 est pétillant(FizzBuzzTest.java:9)

Green

Green a une implémentation ** minimum ** qui passera le test. À ce stade, s'il n'y a pas d'erreur dans le code de test (conception), ne le modifiez pas du tout. Exécutez la distance la plus courte jusqu'à la route pointée vers l'implémentation. Par exemple, peu importe à quel point vous connaissez la réponse, n'écrivez pas de code comme celui-ci: J'expliquerai plus tard pourquoi vous ne devriez pas écrire la réponse.

public class FizzBuzz {

    public static String fizzbuzz(int num) {
        if(num % 3 == 0) {
            return "fizz";
        }
        else {
            return null;
        }
    }
}

La mise en œuvre minimale est la suivante.

public class FizzBuzz {

    public static String fizzbuzz(int num) {
        return "fizz";
    }
}

Refactor

S'il n'y a rien de particulier, il sera ignoré.

Rouge à nouveau

C'est le prochain cycle TDD. La chose à faire est la même. Écrivez un test qui a échoué et pointez sur le chemin suivant.

public class FizzBuzzTest {
    @Test
public void Le numéro 3 est pétillant() {
        assertThat(FizzBuzz.fizzbuzz(3), is("fizz"));
    }

    @Test
public void Le numéro 5 est buzz() {
        assertThat(FizzBuzz.fizzbuzz(5), is("buzz"));
    }
}

Maintenant c'est une erreur car c'est un homme qui retourne "pétillant" quel que soit le numéro qui vient.

FizzBuzzTest >Le numéro 5 est le buzz FAILED
    java.lang.AssertionError:
    Expected: is "buzz"
         but: was "fizz"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.junit.Assert.assertThat(Assert.java:956)
        at org.junit.Assert.assertThat(Assert.java:923)
        at FizzBuzzTest.Le chiffre 5 fait le buzz(FizzBuzzTest.java:14)

Deuxième fois vert

Bien sûr, n'écrivez pas la réponse soudainement comme avant. Gardez à l'esprit uniquement la mise en œuvre minimale. N'utilisez pas votre tête. Pensez à passer au cycle suivant à un bon rythme.

public class FizzBuzz {

    public static String fizzbuzz(int num) {
        if(num == 3) {
            return "fizz";
        } else {
            return "buzz";
        }
    }
}

Refactoring ignoré à nouveau

Ça à l'air bon ...

Il est temps de comprendre Red3

Insérons un multiple de 3 autre que 3.

public class FizzBuzzTest {
    @Test
public void Le numéro 3 est pétillant() {
        assertThat(FizzBuzz.fizzbuzz(3), is("fizz"));
    }

    @Test
public void Le nombre 6 est pétillant() {
        assertThat(FizzBuzz.fizzbuzz(6), is("fizz"));
    }

    @Test
public void Le numéro 5 est buzz() {
        assertThat(FizzBuzz.fizzbuzz(5), is("buzz"));
    }
}

Il entre dans la clause else et renvoie «" buzz "», donc il devient Rouge.

FizzBuzzTest >Le numéro 6 est Fizz FAILED
    java.lang.AssertionError:
    Expected: is "fizz"
         but: was "buzz"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.junit.Assert.assertThat(Assert.java:956)
        at org.junit.Assert.assertThat(Assert.java:923)
        at FizzBuzzTest.Le chiffre 6 est pétillant(FizzBuzzTest.java:14)

Enfin implémenté Green

Si vous voulez pousser l'implémentation minimale, vous pouvez écrire à l'infini le mauvais code suivant, mais revenons aux exigences et implémentons-le.

public class FizzBuzz {

    public static String fizzbuzz(int num) {
        //Comme prévu, c'est déconner!
        if(num == 3 || num == 6){
            return "fizz";
        } else {
            return "buzz";
        }
    }
}

Oui. C'est une implémentation simple! Demandons-nous pourquoi nous ne devrions pas faire cela soudainement ici. Disons que vous avez cette implémentation dans le cas de num 3. Alors écririez-vous un test quand num est 6? Puisque les êtres humains travaillent essentiellement vers ceux qui sont à l'aise, il est probable qu'ils n'écriront pas. Puisque FizzBuzz est le thème cette fois, je reconnais que "ce genre de chose, vous ne pouvez pas faire d'erreur", mais les êtres humains sont des créatures qui font des erreurs, et même les implémentations simples qui sont habituellement faites ont tendance à sauter la vérification et à faire des erreurs.

public class FizzBuzz {

    public static String fizzbuzz(int num) {
        if(num % 3 == 0) {
            return "fizz";
        } else {
            return "buzz";
        }
    }
}

Je voudrais arrêter le cycle de test ici et le résumer. Le point important ici est qu'en commençant le cycle de test à partir du test en premier (rouge en premier), vous pouvez empêcher l'implémentation de dominer et obtenir la garantie que l'implémentation est couverte par le test et que le test sera insuffisant. Et il était très important de résoudre le même problème que Test First en faisant des petits pas, et de réduire la granularité des problèmes qui sont confrontés à la fois et d'augmenter le rythme de mise en œuvre (ne pas utiliser le cerveau). .. Pour ceux qui n'ont jamais fait de TDD auparavant, changer d'état d'esprit est très important, il est donc important de ** s'entraîner quotidiennement **. Aucun athlète ne peut jouer un rôle actif sans s'entraîner. Essayez de protéger le cycle TDD d'un exemple simple et ayez une idée du pas de bébé.

Vitesse et quantité d'essai

Le fait que le TDD soit lent ou pas est souvent soulevé comme un point de l'ordre du jour. La vitesse de développement sera-t-elle ralentie en écrivant le test? Prenons l'exemple FizzBuzz ci-dessus. Implémentez FizzBuzz en une seule fois. Voulez-vous le livrer tel quel? Probablement pas. Je ne sais pas si c'est via l'interface utilisateur ou la CLI, mais vous l'exécuterez probablement et vérifierez.

printf Voulez-vous déboguer? Si tel est le cas, vous devriez peut-être le vérifier en suivant la procédure suivante.

―― 3 est pétillant --Suivant, 5 est le buzz

Cette? Vous savez quelque chose ... C'est vrai. TDD est le même flux que vous vérifiez réellement l'application. Quelle est la différence? La confirmation d'exécution n'est qu'une vérification ad hoc. Lorsqu'un changement se produit dans le code, la confirmation n'a plus de sens et seul «vous» la confirmez. Imaginez qu'il s'agisse d'un entrelacement complexe de fonctionnalités comme un vrai produit. Voulez-vous TDD? Voulez-vous vérifier manuellement?

En gros, je continuerai à écrire sur la quantité de tests jusqu'à ce que mon anxiété disparaisse. En plus de cela, le code dupliqué augmentera dans le code de test. Dans ce cas, il est judicieux d'essayer une refactorisation appropriée et des tests paramétrés.

Recommended Posts

Résumé de la formation TDD
Résumé
Résumé orienté objet
Rspec, TDD (1)
résumé du ransack