[JAVA] Implementierung von FizzBuzz-Problemen in der testgetriebenen Entwicklung (Praxis)

2017.07.02 Bearbeitet.

Weiter geht es mit der Vorbereitung, die neulich veröffentlicht wurde. Dieses Mal werden wir mit der TDD des FizzBuzz-Problems als praktische Version fortfahren.

Überprüfung der Vorbereitung und des Ablaufs der Praxis

Vorteile von TDD

FizzBuzz Problemanforderungen

Bedarf Inhalt
Anforderung 1 Gibt den als Argument verwendeten Wert als Zeichenfolge zurück
Anforderung 2 Wenn es sich jedoch um ein Vielfaches von 3 handelt, wird "Fizz" zurückgegeben.
Anforderung 3 Wenn es sich jedoch um ein Vielfaches von 5 handelt, wird "Buzz" zurückgegeben.
Anforderung 4 Wenn es sich jedoch um ein Vielfaches von 3 und 5 handelt, wird "FizzBuzz" zurückgegeben.
Anforderung 5 Fehler, wenn das Argument keine Zahl von 1 bis 100 ist

Ablauf der Praxis

Da es überflüssig wäre, alle Anforderungen 1 bis 5 einzuführen, wird in diesem Artikel nur Anforderung 1 eingeführt. Das vollständige Programm finden Sie am Ende des Artikels.


Anforderung 1: Gibt den als Argument verwendeten Wert als Zeichenfolge zurück

Stellen Sie zunächst sicher, dass der Test fehlschlägt

Bei der Implementierung von Anforderung 1 wurden die Testklasse (FizzBuzzTest.java) und die Testzielklasse (FizzBuzz.java) zunächst wie folgt implementiert.

FizzBuzzTest.java


public class FizzBuzzTest {
    @Test
public void Gibt 1 zurück, wenn 1 als Argument angegeben wird() {
        FizzBuzz fizzbuzz = new FizzBuzz();
        assertEquals("1", fizzbuzz.response(1));
    }
}

FizzBuzz.java


public class FizzBuzz {
    //Gibt null zurück(Gibt keinen Wert zurück)
    public String response(int num) {
        return null;
    }
}

Bewegen Sie den Cursor auf FizzBuzzTest, klicken Sie mit der rechten Maustaste auf> Ausführen als ... -> drücken Sie JUnit Test. Wenn Sie den Test ausführen, ist das Ergebnis natürlich ein roter Balken, der den Testfehler anzeigt.

4.JPG

Dieser ** Testfehler ** ist eigentlich der Punkt. Wenn Sie eine neue Klasse entwickeln, die wie dieses Mal getestet werden soll, können Sie überprüfen, ob ** JUnit den Erfolg oder Misserfolg des Tests richtig beurteilt **.

Wenn Sie einen neuen Test hinzufügen und der Test erfolgreich ist, wenn Sie eine Funktion zur ** vorhandenen Methode der zu testenden Klasse hinzufügen, sind möglicherweise einige der zusätzlichen Funktionen bereits implementiert. Sex durchschauen.

Implementieren Sie ein Programm, das den Test besteht

Implementieren Sie als Nächstes die zu testende Methode, die den Test besteht.

FizzBuzz.java


    public String response(int num) {
        return "1";
    }

Wenn Sie den Test wie zuvor ausführen, ist der Test natürlich erfolgreich.

5.JPG

Bei der Entwicklung von TDD beginnen wir damit, ** ein Programm zu schreiben, das den Test besteht **. Bis wir uns daran gewöhnt haben, werden wir die Testfälle nicht von Anfang an eingrenzen, und selbst wenn es ein wenig einfach ist, werden wir uns aufbauen, um jeden Zweck einzeln zu erreichen.

Versuchen wir es jetzt, auch wenn das Argument 2 ist.

FizzBuzzTest.java


    @Test
public void Gibt 1 zurück, wenn 1 als Argument angegeben wird() {
        FizzBuzz fizzbuzz = new FizzBuzz();
        assertEquals("1", fizzbuzz.response(1));
    }
    @Test
public void Gibt 2 zurück, wenn 2 als Argument angegeben wird() {
        FizzBuzz fizzbuzz = new FizzBuzz();
        assertEquals("2", fizzbuzz.response(2));
    }

FizzBuzz.java


    public String response(int num) {
        return "1";
    }

Das Ergebnis der Testausführung lautet wie folgt, und ein roter Balken zeigt an, dass der Test fehlgeschlagen ist.

6.JPG

Implementieren Sie ein Programm, das die Anforderungen erfüllt und den Test besteht

Es gibt im Allgemeinen zwei Möglichkeiten aus dem hinzugefügten Testfehler:

Wenn wir auf das Ausführungsergebnis von JUnit zurückblicken, können wir der folgenden Beschreibung entnehmen, dass das Ausführungsergebnis 1 war, obwohl wir erwartet haben, dass das Ausführungsergebnis 2 ist, was nicht dem erwarteten Wert entspricht.

org.junit.ComparisonFailure: expected:<[2]> but was:<[1]>

Ändern Sie daher das Testzielprogramm FizzBuzz.java wie folgt entsprechend der Anforderung: Der als Argument verwendete Wert wird als Zeichenfolge zurückgegeben.

FizzBuzz.java


    public String response(int num) {
        return String.valueOf(num);
    }

Nachdem bestätigt wurde, dass der Test erfolgreich ist, ist die Implementierung von Anforderung 1 abgeschlossen.

7.JPG

In ähnlicher Weise lauten FizzBuzzTest.java und FizzBuzz.java, die die Anforderungen 2 bis 5 implementieren und die Testfälle der entsprechenden Klasse auf eins eingrenzen, wie folgt.

FizzBuzzTest.java


public class FizzBuzzTest {
    private FizzBuzz fizzbuzz;

    @Before
öffentliche nichtige Instanziierung() {
        fizzbuzz = new FizzBuzz();
    }

    @Test
public void Gibt 1 zurück, wenn 1 als Argument angegeben wird() {
        assertEquals("1", fizzbuzz.response(1));
    }

    @Test
public void Gibt Fizz mit 3 Argumenten zurück() {
        assertEquals("Fizz", fizzbuzz.response(3));
    }

    @Test
public void Gibt Buzz mit 5 Argumenten zurück() {
        assertEquals("Buzz", fizzbuzz.response(5));
    }

    @Test
public void Gibt FizzBuzz mit 15 Argumenten zurück() {
        assertEquals("FizzBuzz", fizzbuzz.response(15));
    }

    @Test(expected = IndexOutOfBoundsException.class)
public void Wenn das Argument mit 0 angegeben wird, tritt ein Fehler auf.() {
        fizzbuzz.response(0);
    }

    @Test(expected = IndexOutOfBoundsException.class)
Wenn 101 für das Argument public void angegeben wird, tritt ein Fehler auf.() {
        fizzbuzz.response(101);
    }

    @Test
public void Gibt Buzz zurück, wenn 100 als Argument angegeben wird() {
        assertEquals("Buzz", fizzbuzz.response(100));
    }
}

FizzBuzz.java


public class FizzBuzz {
    public String response(int num) {
        if(num < 1 || num > 100) {
            throw new IndexOutOfBoundsException();
        }

        StringBuilder result = new StringBuilder();

        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();
    }
}

Bonus: Strukturierung von Testklassen

Aus dem obigen Namen der Testmethode FizzBuzzTest.java können Sie erkennen, was der Test zu überprüfen ist, damit Sie ihn so beenden können, wie er ist. Es ist jedoch einfacher zu verstehen, ** welcher Anforderung jede Testmethode entspricht ** Schließlich ** strukturieren Sie die Testklasse **.

Bei der Strukturierung von Testklassen wird mithilfe der Annotation @RunWith (Enclosed.class) von JUnit eine innere Klasse für jede Testkategorie festgelegt, um Testfälle zu klassifizieren. [^ 1] [^ 2]

Dieser Test kann je nach Anforderung in die folgenden Kategorien unterteilt werden.

Artikelnummer Kategorie
1 Argumente sind keine Vielfachen von 3 und 5
2 Ein Vielfaches mit nur 3 Argumenten
3 Ein Vielfaches mit nur 5 Argumenten
4 Argumente sind Vielfache von 3 und 5
5 Das Argument ist ein ungültiger Grenzwert(Keine Zahl von 1 bis 100)
6 Argument ist ein gültiger Grenzwert(Zahlen von 1 bis 100)

Legen Sie die innere Klasse für jede der oben genannten Kategorien fest und schreiben Sie FizzBuzzTest.java wie folgt neu.

FizzBuzzTest.java


@RunWith(Enclosed.class)
public class FizzBuzzTest {
    
    
public static class Argument ist kein Vielfaches von 3 und 5{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Gibt 1 zurück, wenn 1 als Argument angegeben wird() {
            assertEquals("1", fizzbuzz.response(1));
        }
    }

öffentliche statische Klasse Ein Vielfaches von 3 mit nur 3 Argumenten{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Gibt Fizz mit 3 Argumenten zurück() {
            assertEquals("Fizz", fizzbuzz.response(3));
        }
    }

öffentliche statische Klasse Ein Vielfaches von 5 mit nur 5 Argumenten{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Gibt Buzz mit 5 Argumenten zurück() {
            assertEquals("Buzz", fizzbuzz.response(5));
        }
    }

öffentliche statische Klasse Argumente sind Vielfache von 3 und 5{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Gibt FizzBuzz mit 15 Argumenten zurück() {
            assertEquals("FizzBuzz", fizzbuzz.response(15));
        }
    }

Das öffentliche statische Klassenargument ist ein ungültiger Grenzwert{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test(expected = IndexOutOfBoundsException.class)
public void Wenn das Argument mit 0 angegeben wird, tritt ein Fehler auf.() {
            fizzbuzz.response(0);
        }

        @Test(expected = IndexOutOfBoundsException.class)
Wenn 101 für das Argument public void angegeben wird, tritt ein Fehler auf.() {
            fizzbuzz.response(101);
        }
    }

Das öffentliche statische Klassenargument ist ein gültiger Grenzwert{
        FizzBuzz fizzbuzz = new FizzBuzz();

        @Test
public void Gibt 1 zurück, wenn 1 als Argument angegeben wird() {
            assertEquals("1", fizzbuzz.response(1));
        }

        @Test
public void Gibt Buzz zurück, wenn 100 als Argument angegeben wird() {
            assertEquals("Buzz", fizzbuzz.response(100));
        }
    }
}

Führen Sie den Test nach dem Umschreiben natürlich aus, um sicherzustellen, dass alles erfolgreich ist.

構造化.PNG

Ich denke, dass die Testergebnisse es auch einfacher machen zu verstehen, für welche Anforderungen die Testfälle sind, als dass die Testfälle in einer Reihe angeordnet sind.

Dies ist das Ende der praktischen Ausgabe. Diesmal war es TDD für relativ einfache Anforderungen, aber in Zukunft werde ich TDD definitiv ausprobieren, wenn komplexere Anforderungen implementiert werden, und seine Auswirkungen und Einschränkungen erkennen.

Verweise


[^ 1]: Die Annotation @RunWith (Enclosed.class) erkennt alle inneren Klassen als getestete Klasse und ermöglicht es ihnen, die Methoden mit der Annotation @Test in jeder inneren Klasse auszuführen.

[^ 2]: Wenn Ihnen die innere Klasse nicht gefällt, können Sie für jede Testkategorie eine Testmethode erstellen und den Testfall ausdrücken, indem Sie mehrere Zusicherungen festlegen.

Recommended Posts

Implementierung von FizzBuzz-Problemen in der testgetriebenen Entwicklung (Praxis)
Implementierung von FizzBuzz-Problemen in der testgetriebenen Entwicklung (Vorbereitung)
Testgetriebene Entwicklung mit der Funktionssprache Elm
FizzBuzz in Java
Implementieren Sie CustomView im Code
Markdown in Rails implementiert
So implementieren Sie eine einzeilige Anzeige von TextView in der Android-Entwicklung