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

Neulich habe ich zum ersten Mal an der Entwicklerveranstaltung von Microsoft de: code2017 teilgenommen. Es war sehr interessant, sich über eine Vielzahl von Themen zu informieren, beispielsweise über das Verwalten und Ändern von Legacy-Entwicklungsstandorten anhand der neuesten technologischen Trends.

Darunter die testgetriebene Entwicklung des ** FizzBuzz-Problems, das Gegenstand der Live-Codierung für die Sitzung war DO03 Testgetriebene Entwicklung in 50 Minuten Die Entwicklung ** war sehr beeindruckend.

Was ist also überhaupt ein Test (Unit Test)? Während ich zurückblickte, versuchte ich es auf meine eigene Weise zu üben.

Da es anscheinend länger dauert, wenn Sie die Übungsinhalte der Reihe nach befolgen, werde ich sie in zwei Teilen veröffentlichen: ** Vorbereitung ** und ** Übung **. Diesmal ist es ** Vorbereitung **.

Was ist ein Komponententest? </ I>

In einem Wort

Ein Komponententest ist ein Test, mit dem überprüft wird, ob ein Programm gemäß den Spezifikationen in kleinen Einheiten wie Klassen und Methoden funktioniert.

Unit-Test-Methode

Es gibt drei Haupttypen:

  • __ Funktionsbestätigungstest __ Stellen Sie sicher, dass das Programm den Spezifikationen entspricht
  • __ Kontrollflusstest __ Überprüfen Sie, ob alle Anweisungen und bedingten Verzweigungen ausgeführt werden
  • __ Datenflusstest __ Überprüfen Sie, ob die Daten (insbesondere die Daten, die für andere freigegeben werden) definiert, verwendet und freigegeben wurden

Warum brauchen Sie einen Unit-Test?

Es scheint eine Idee zu geben, dass Unit-Tests nutzlos sind [^ 1], aber ich denke, dass dies in den folgenden Punkten notwendig ist.

  • Bauen Sie Qualität von Kleinteilen bis Bottom-up auf.

  • Erleichtert die Funktionsprüfung nach Refactoring- und Spezifikationsänderungen und verbessert die Wartbarkeit des Systems.

Was ist testgetriebene Entwicklung? </ I>

In einem Wort

Es ist eine Entwicklungsmethode, die die folgenden drei Zyklen für jede Funktion der Spezifikation wiederholt.

  1. Schreiben Sie den Testcode
  2. Implementieren Sie ein Programm, das den Test besteht
  3. Refactor

Im xUnit-Framework wird dieser Zyklus anhand der Farbe der Balkenanzeige beschrieben, wenn der Test fehlschlägt / erfolgreich ist. ROT </ font> - GRÜN </ font> --REFACTOR Auch genannt.

Warum sollten Sie sich für eine testgetriebene Entwicklung entscheiden?

Die tatsächliche Wahl der testgetriebenen Entwicklung hängt von der Projektsituation ab, aber ich denke, die folgenden Vorteile gelten für jedes Projekt.

  • Weil es möglich ist, einen sauberen Code zu realisieren, der funktioniert (sauberer Code, der funktioniert).
  • Weil es möglich ist, die Nacharbeit bei der Behebung des gesamten Einflussbereichs der Fehler zu reduzieren, die im Test nach Abschluss der Implementierung aufgetreten sind.
  • Da ein hoch wartbares Design realisiert werden kann (einfach zu testen = stark gegen Änderungen und hoch wartbar able schwer zu testen = es gibt Raum für Designverbesserungen)

Nun machen wir uns bereit für die ** testgetriebene Entwicklung des FizzBuzz-Problems **.

Vorbereiten der Betriebsumgebung </ i>

Umgebungseinstellung

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

Ein Projekt erstellen

Führen Sie die folgenden Schritte aus, um ein Projekt zu erstellen.

  1. Starten Sie STS (Spring Tool Suite).
  2. Klicken Sie mit der rechten Maustaste in Paket-Explorer-> Neu-> Maven-Projekt
  3. Aktivieren Sie "Einfaches Projekt erstellen (Auswahl des Archetyps überspringen)" und klicken Sie auf "Weiter"
  4. Geben Sie einen beliebigen Paketnamen in Gruppen-ID und Artefakt-ID ein und klicken Sie auf Fertig stellen

Stellen Sie sicher, dass pom.xml direkt unter dem erstellten Projekt erstellt wird.

checkPom.JPG

pom.xml Einstellungen

Fügen Sie als Nächstes die folgenden Einstellungen zu pom.xml hinzu, um JUnit zu verwenden.

pom.xml


<!--Auszug nur für verwandte Teile-->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
Ergänzung

Wenn die Version der JRE-Bibliothek nicht 1.8 ist, fügen Sie die Einstellung maven-compiler-plugin zu pom.xml hinzu.

JavaVersion.JPG

pom.xml


<!--Auszug nur für verwandte Teile-->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
           </plugin>
        </plugins>
    </build>

Definition der FizzBuzz-Problemanforderung </ i>

Nachdem die Umgebung eingerichtet ist, müssen die zu implementierenden Anforderungen definiert werden.

FizzBuzz Problem

Schreiben Sie ein Programm, das Zahlen von 1 bis 100 druckt. Wenn es sich jedoch um ein Vielfaches von 3 handelt, drucken Sie "Fizz" anstelle einer Zahl. Wenn es sich um ein Vielfaches von 5 handelt, drucken Sie "Buzz". Wenn es sich um ein Vielfaches von 3 und 5 handelt, drucken Sie "Fizz Buzz".

Es scheint, dass es ursprünglich ein englischsprachiges Sprachspiel war.

Geteilte funktionale Anforderungen für FizzBuzz-Probleme

Aus dem obigen Problem werden wir die Schlüsselwörter extrahieren, die Anforderungen aufteilen und den Implementierungsteil definieren.

Schlüsselwörter extrahieren </ i>

Extrahieren Sie den Teil, der dem Befehl oder der Bedingung entspricht, als Schlüsselwort. 要件抜き出し.png

  • Zahlen von 1 bis 100
  • Drucken
  • "Fizz", wenn es ein Vielfaches von 3 ist
  • "Buzz", wenn es ein Vielfaches von 5 ist
  • "FizzBuzz" für Vielfache von 3 und 5

Definieren Sie den zu implementierenden Teil </ i>

Definieren Sie aus den Schlüsselwörtern den Teil, der in der zu testenden Klasse implementiert werden soll. Hier bleibt die Druckfunktion dem Aufrufer der FizzBuzz-Klasse überlassen, und die FizzBuzz-Klasse hat die Funktion, die Zeichenfolge zurückzugeben, die der Aufrufer drucken möchte.

  • Nehmen Sie eine Zahl als Argument
  • Gibt eine Zeichenfolge zurück ~~ Print ~~
  • Argumentwert
  • Wenn es sich jedoch um ein Vielfaches von 3 handelt, wird "Fizz"
  • Wenn es sich jedoch um ein Vielfaches von 5 handelt, wird "Buzz"
  • Bei Vielfachen von 3 und 5 wird jedoch "FizzBuzz"
  • Argumente von 1 bis 100

Bestimmen Sie die Reihenfolge der Implementierung </ i>

Mit welcher der oben genannten Funktionen möchten Sie beginnen, auch wenn Sie den Klassenein- und -ausgang "Nehmen Sie eine Zahl" und "Geben Sie eine Zeichenfolge zurück" ausschließen? Ich denke, die Frage bleibt. Ich denke, es hängt von der Zeit und dem Fall ab, aber ich habe die Reihenfolge aus den folgenden Funktionen festgelegt. [^ 2]

  • __ Keine Ausnahmen __ "Das Argument ist von 1 bis 100" = "Wenn das Argument 0 oder weniger oder 101 oder mehr ist, tritt eine Ausnahme auf", also machen Sie es zuletzt
  • __ Keine Verzweigungsbedingung __ Vorrang haben Artikel, die "jedoch" nicht ankommen
  • __ Verzweigungsbedingungen sind einfacher __ "Für Vielfache von 3 und 5" hat zwei Bedingungen, also machen wir es später
  • Erfüllen Sie die endgültigen Anforderungen schneller (siehe Hinweis)

Daher werden wir die FizzBuzz-Klasse testen und entwickeln, die eine Zahl als Argument verwendet und eine Zeichenfolge in der folgenden Reihenfolge zurückgibt.

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

JUnit-Funktionsprüfung </ i>

Zunächst möchte ich Testcode schreiben ... aber vorher muss ich bestätigen, dass JUnit korrekt installiert ist.

Bereiten Sie insbesondere die Testklasse FizzBuzzTest.java vor, schreiben Sie ein leeres Testprogramm und führen Sie den Test aus.

Erstellen von FizzBuzzTest.java

Bereiten Sie zunächst die Testklasse wie folgt vor.

  1. Setzen Sie den Cursor auf "src / __ test__ / java" und klicken Sie mit der rechten Maustaste auf> Neu-> Paket
  2. Geben Sie einen beliebigen Paketnamen in das Feld Name ein und klicken Sie auf Fertig stellen
  3. Setzen Sie den Cursor auf das erstellte Paket, klicken Sie mit der rechten Maustaste -> klicken Sie auf Klasse
  4. Geben Sie FizzBuzzTest in das Feld Name ein und klicken Sie auf Fertig stellen (andere Einstellungen bleiben bei ihren Standardeinstellungen).
CreateFizzBuzzTest.JPG

Die Projektstruktur nach dem Erstellen von FizzBuzzTest.java lautet wie folgt.

FizzBuzzTestProject.JPG

Erstellen Sie ein leeres Testprogramm

Implementieren Sie als Nächstes eine leere Testmethode, die in der erstellten Datei FizzBuzzTest.java nichts bewirkt.

FizzBuzzTest.java



import org.junit.Test;

public class FizzBuzzTest {
    @Test
public void JUnit-Betriebstest() {
        
    }
}

Testlauf

Platzieren Sie den Cursor auf der JUnit-Operationstestmethode der von Ihnen erstellten FizzBuzzTest-Klasse und klicken Sie mit der rechten Maustaste auf> Ausführen als-> JUnit-Test, um den Test auszuführen.

Dann sehen Sie einen grünen Balken, der anzeigt, dass der Test erfolgreich war, wie in der folgenden Abbildung gezeigt.

JUnit確認テスト.JPG

Dies zeigt, dass JUnit standardmäßig arbeitet und JUnit verwenden kann. Wenn der Test hingegen fehlschlägt, können Sie Fehler in der Testumgebung feststellen. Beispielsweise war die Maven-Installation nicht erfolgreich.


Nachdem Sie bestätigt haben, dass JUnit einwandfrei funktioniert, ist die ** Vorbereitung ** beendet.

Hier werde ich die endgültige Projektstruktur und den Programminhalt mit den Worten "Fazit kommt zuerst" veröffentlichen. [^ 3]

Projektstruktur
Project.JPG
Testprogramm

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 {

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 gültiger Grenzwert{
        FizzBuzz fizzbuzz = new FizzBuzz();
        
        @Test
public void Gibt 1 zurück, wenn Argument 1 angegeben ist() {
            assertEquals("1", fizzbuzz.response(1));
        }

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

Das öffentliche statische Klassenargument ist ein ungültiger Grenzwert{
        FizzBuzz fizzbuzz = new FizzBuzz();
        
        @Test(expected = IndexOutOfBoundsException.class)
public void Ein Fehler tritt auf, wenn das Argument 0 angegeben wird.() {
            fizzbuzz.response(0);
        }

        @Test(expected = IndexOutOfBoundsException.class)
Ein öffentlicher void-Fehler tritt auf, wenn das Argument 101 angegeben wird() {
            fizzbuzz.response(101);
        }
    }
}
Zu testendes Programm

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

Das nächste Mal möchte ich als ** Übung ** veröffentlichen, wie ich mit der Implementierung der folgenden Testklasse (FizzBuzzTest.java) und der Testzielklasse (FizzBuzz.java) fortgefahren bin.

Referenz


[^ 1]: Ich habe nur die Zusammenfassung gelesen, aber die ursprüngliche Geschichte lautet [Warum \ -Most \ -Unit \ -Testing \ -is \ -Waste \ .pdf](http://rbcs-us.com/ Dokumente / Warum-die-meisten-Unit-Tests-sind-Abfall.pdf) Es ist geschrieben in.

[^ 2]: Wenn beispielsweise in einem Filmreservierungssystem mit mehreren Rabattoptionen gemäß den Benutzereigenschaften die letzte Anforderung "die Option anwenden, die den Rabattsatz erhöht" lautet, wird aus der Bedingung der Benutzereigenschaften heraus, dass der Rabattsatz hoch ist Ich werde es testen.

[^ 3]: Es gibt einige Unterschiede zur Live-Codierung in de: code, auf die ich mich bezog, da dies das Ergebnis meiner eigenen Praxis war und einige Teile aus zeitlichen Gründen in de: code weggelassen wurden.