[JAVA] Implémentation des problèmes FizzBuzz dans le développement piloté par les tests (préparation)

L'autre jour, j'ai participé pour la première fois à l'événement développeur de Microsoft de: code2017. Il était très intéressant d'entendre parler d'un large éventail de thèmes, tels que la gestion et la modification des sites de développement hérités à partir des dernières tendances technologiques.

Parmi eux, le développement piloté par les tests du problème ** FizzBuzz, qui a fait l'objet d'un codage en direct pour la session Développement piloté par les tests DO03 en 50 minutes Le développement ** était très impressionnant.

Alors, qu'est-ce qu'un test (test unitaire) en premier lieu? En regardant en arrière, j'ai essayé de le pratiquer à ma manière.

Comme il semble que ce sera plus long si vous suivez le contenu de la pratique dans l'ordre, je le posterai en deux parties, ** Préparation ** et ** Pratique **. Cette fois, c'est la ** préparation **.

Qu'est-ce qu'un test unitaire? </ I>

En un mot

Un test unitaire est un test pour vérifier si un programme fonctionne selon les spécifications en petites unités telles que les classes et les méthodes.

Méthode de test unitaire

Il existe trois types principaux:

  • __ Test de confirmation des fonctions __ Assurez-vous que le programme fonctionne selon les spécifications
  • __ Test de débit de contrôle __ Vérifiez si toutes les instructions et branches conditionnelles sont exécutées
  • __ Test de flux de données __ Vérifiez si les données (en particulier les données partagées avec d'autres) sont définies, utilisées et publiées

Pourquoi vous avez besoin d'un test unitaire

Il semble y avoir une idée que les tests unitaires sont inutiles [^ 1], mais j'estime que c'est nécessaire dans les points suivants.

  • Construisez la qualité des petites pièces vers le haut.

  • Facilite la vérification du fonctionnement après la refactorisation et les changements de spécifications et améliore la maintenabilité du système.

Qu'est-ce que le développement piloté par les tests? </ I>

En un mot

C'est une méthode de développement qui répète les trois cycles suivants pour chaque fonction de la spécification.

  1. Écrire le code de test
  2. Mettre en œuvre un programme qui réussit le test
  3. Refactoriser

Dans le framework xUnit, ce cycle est décrit à partir de la couleur de l'affichage de la barre lorsque le test échoue / réussit. RED </ font> - GREEN </ font> --REFACTOR Aussi appelé.

Pourquoi choisir le développement piloté par les tests

Le choix réel du développement piloté par les tests dépend de la situation du projet, mais je pense que les avantages suivants s'appliquent à n'importe quel projet.

  • Parce qu'il est possible de réaliser un code propre qui fonctionne (code propre qui fonctionne).
  • Parce qu'il est possible de réduire le retravail de la correction de toute la plage affectée du bogue qui est apparu dans le test une fois l'implémentation terminée.
  • Parce qu'une conception hautement maintenable peut être réalisée (facile à tester = forte contre les changements et hautement maintenable ↔ difficile à tester = place pour l'amélioration de la conception)

Maintenant, préparons-nous pour ** le développement piloté par les tests du problème FizzBuzz **.

Préparation de l’environnement d’exploitation </ i>

Cadre environnemental

Type Material Version
Language Java (JDK) 1.8.0_111
IDE Spring Tool Suite 3.8.2
Build Maven 3.3.9
Test JUnit 4.12

Créer un projet

Suivez les étapes ci-dessous pour créer un projet.

  1. Lancez STS (Spring Tool Suite).
  2. Cliquez avec le bouton droit dans l'Explorateur de packages-> Nouveau-> Projet Maven
  3. Cochez "Créer un projet simple (ignorer la sélection d'archétype)" et cliquez sur Suivant
  4. Entrez un nom de package dans l'ID de groupe et l'ID d'artefact et cliquez sur Terminer

Assurez-vous que pom.xml est créé directement sous le projet créé.

checkPom.JPG

Paramètres pom.xml

Ensuite, ajoutez les paramètres suivants à pom.xml pour utiliser JUnit.

pom.xml


<!--Extrait uniquement pour les pièces connexes-->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
Supplément

Si la version de la bibliothèque JRE n'est pas 1.8, ajoutez le paramètre maven-compiler-plugin à pom.xml.

JavaVersion.JPG

pom.xml


<!--Extrait uniquement pour les pièces connexes-->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
           </plugin>
        </plugins>
    </build>

Définition des exigences du problème FizzBuzz </ i>

Maintenant que l'environnement est en place, il est temps de définir les exigences à mettre en œuvre.

Problème FizzBuzz

Écrivez un programme qui imprime des nombres de 1 à 100. Cependant, s'il s'agit d'un multiple de 3, imprimez «Fizz» au lieu d'un nombre, s'il s'agit d'un multiple de 5, imprimez «Buzz», et s'il s'agit d'un multiple de 3 et 5, imprimez «Fizz Buzz».

Il semble que c'était à l'origine un jeu de langue anglaise.

Diviser les exigences fonctionnelles pour les problèmes FizzBuzz

À partir du problème ci-dessus, nous allons extraire les mots-clés, diviser les exigences et définir la partie implémentation.

Extraire les mots-clés </ i>

Extrayez la partie correspondant à la commande ou à la condition sous forme de mot-clé. 要件抜き出し.png

  • Nombres de 1 à 100
  • Impression
  • "Fizz" lorsqu'il est un multiple de 3
  • "Buzz" lorsqu'il est un multiple de 5
  • "FizzBuzz" pour les multiples de 3 et 5

Définir la pièce à implémenter </ i>

A partir des mots-clés, définissez la partie à implémenter dans la classe testée. Ici, la fonction à imprimer est laissée à l'appelant de la classe FizzBuzz, et la classe FizzBuzz a la fonction de renvoyer la chaîne de caractères que l'appelant veut imprimer.

  • Prenez un nombre comme argument
  • Renvoie une chaîne ~~ Imprimer ~~
  • Valeur de l'argument
  • Cependant, lorsqu'il est un multiple de 3, "Fizz"
  • Cependant, lorsqu'il est un multiple de 5, "Buzz"
  • Cependant, dans le cas de multiples de 3 et 5, "FizzBuzz"
  • Arguments de 1 à 100

Déterminer l’ordre de mise en œuvre </ i>

Avec laquelle des fonctionnalités ci-dessus voulez-vous commencer, même si vous excluez l'entrée de classe et quittez "prendre un nombre" et "renvoyer une chaîne"? Je pense que la question demeure. Je pense que cela dépend de l'heure et du cas, mais j'ai décidé de l'ordre des fonctions suivantes. [^ 2]

  • __ Aucune exception __ "L'argument est compris entre 1 et 100" = "Si l'argument est 0 ou moins ou 101 ou plus, une exception se produit", alors faites-le durer
  • __ Aucune condition de succursale __ La priorité est donnée aux articles qui «cependant» n'arrivent pas
  • __ Les conditions des succursales sont plus simples __ "Pour les multiples de 3 et 5" a deux conditions, donc nous le ferons plus tard
  • Répondez aux exigences finales plus rapidement (voir note)

Nous allons donc tester et développer la classe FizzBuzz, qui prend un nombre comme argument et renvoie une chaîne de caractères, dans l'ordre suivant.

  1. Renvoie la valeur prise comme argument sous forme de chaîne de caractères
  2. Cependant, s'il s'agit d'un multiple de 3, "Fizz" est renvoyé.
  3. Cependant, s'il s'agit d'un multiple de 5, "Buzz" est renvoyé.
  4. Cependant, s'il s'agit d'un multiple de 3 et 5, "FizzBuzz" est renvoyé.
  5. Erreur si l'argument n'est pas un nombre compris entre 1 et 100

Vérification du fonctionnement de JUnit </ i>

Tout d'abord, j'aimerais écrire du code de test ... mais avant cela, je dois confirmer que JUnit est correctement installé.

Plus précisément, préparez la classe de test FizzBuzzTest.java, écrivez un programme de test vide et exécutez le test.

Création de FizzBuzzTest.java

Tout d'abord, préparez la classe de test selon la procédure suivante.

  1. Placez le curseur sur "src / __ test__ / java", faites un clic droit-> Nouveau-> Package
  2. Entrez un nom de package dans le champ Nom et cliquez sur Terminer
  3. Placez le curseur sur le package créé, faites un clic droit-> cliquez sur Classe
  4. Entrez FizzBuzzTest dans le champ Nom et cliquez sur Terminer (les autres paramètres conservent leurs valeurs par défaut)
CreateFizzBuzzTest.JPG

La structure du projet après la création de FizzBuzzTest.java est la suivante.

FizzBuzzTestProject.JPG

Créer un programme de test vide

Ensuite, implémentez une méthode de test vide qui ne fait rien dans le FizzBuzzTest.java créé.

FizzBuzzTest.java



import org.junit.Test;

public class FizzBuzzTest {
    @Test
test de fonctionnement public void JUnit() {
        
    }
}

Essai

Placez le curseur sur la méthode de test d'opération JUnit de la classe FizzBuzzTest que vous avez créée et cliquez avec le bouton droit sur -> Exécuter en tant que -> Test JUnit pour exécuter le test.

Ensuite, vous verrez une barre verte indiquant que le test a réussi, comme indiqué dans la figure ci-dessous.

JUnit確認テスト.JPG

À partir de là, vous pouvez voir que JUnit fonctionne par défaut et est prêt à utiliser JUnit. Inversement, si le test échoue, vous pouvez découvrir des failles dans l'environnement de test, par exemple, l'installation de Maven a échoué.


Maintenant que vous avez confirmé que JUnit fonctionne correctement, la ** Préparation ** est terminée.

Ici, je publierai la structure finale du projet et le contenu du programme en disant "La conclusion vient en premier". [^ 3]

Structure du projet
Project.JPG
Programme d'essai

FizzBuzzTest.java


package com.example;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;

@RunWith(Enclosed.class)
public class FizzBuzzTest {

L'argument de classe statique publique n'est pas un multiple de 3 et 5{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Renvoie 1 si 1 est donné comme argument() {
            assertEquals("1", fizzbuzz.response(1));
        }
    }
    
public static class Un multiple de 3 avec seulement 3 arguments{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Renvoie Fizz avec 3 arguments() {
            assertEquals("Fizz", fizzbuzz.response(3));
        }
    }

public static class Un multiple de 5 avec seulement 5 arguments{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Renvoie Buzz avec 5 arguments() {
            assertEquals("Buzz", fizzbuzz.response(5));
        }
    }

public static class Les arguments sont des multiples de 3 et 5{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Renvoie FizzBuzz avec 15 arguments() {
            assertEquals("FizzBuzz", fizzbuzz.response(15));
        }
    }
    
l'argument de classe statique public est une valeur limite valide{
        FizzBuzz fizzbuzz = new FizzBuzz();
        
        @Test
public void Renvoie 1 si l'argument 1 est donné() {
            assertEquals("1", fizzbuzz.response(1));
        }

        @Test
public void Renvoie Buzz avec 100 arguments() {
            assertEquals("Buzz", fizzbuzz.response(100));
        }
    }

L'argument de classe statique public n'est pas valide. Valeur limite{
        FizzBuzz fizzbuzz = new FizzBuzz();
        
        @Test(expected = IndexOutOfBoundsException.class)
public void Une erreur se produit si l'argument 0 est donné.() {
            fizzbuzz.response(0);
        }

        @Test(expected = IndexOutOfBoundsException.class)
une erreur public void se produit si l'argument 101 est donné() {
            fizzbuzz.response(101);
        }
    }
}
Programme à tester

FizzBuzz.java


public class FizzBuzz {

    public String response(int num) {
        StringBuilder result = new StringBuilder();
        
        if(num < 1 || num > 100) {
            throw new IndexOutOfBoundsException();
        }
        
        if(num % 3 == 0) {
            result.append("Fizz");
        }

        if(num % 5 == 0) {
            result.append("Buzz");
        }
        
        if(result.length() == 0) {
            result.append(String.valueOf(num));
        }

        return result.toString();
    }
}

La prochaine fois, je voudrais publier en tant que ** Practice ** comment j'ai procédé à l'implémentation de la classe de test suivante (FizzBuzzTest.java) et de la classe cible de test (FizzBuzz.java).

référence


[^ 1]: Je n'ai lu que le résumé, mais l'histoire originale est [Why \ -Most \ -Unit \ -Testing \ -is \ -Waste \ .pdf](http://rbcs-us.com/ documents / Pourquoi la plupart des tests unitaires sont des déchets.pdf) Il est écrit.

[^ 2]: par exemple, dans un système de réservation de films qui propose plusieurs options de remise en fonction des caractéristiques de l'utilisateur, si l'exigence finale est "appliquer l'option qui augmente le taux de remise", alors à partir de la condition caractéristique de l'utilisateur que le taux de remise est élevé Je vais le tester.

[^ 3]: Il y a quelques différences par rapport au codage en direct de de: code auquel j'ai fait référence parce que c'était le résultat de ma propre pratique et que certaines parties ont été omises dans de: code en raison de contraintes de temps.