[JAVA] Halten Sie das praktische Bild und das wesentliche Bild gedrückt, um TDD anzugehen

Einführung

Dieser Artikel wurde verfasst, um TDD anzugehen und ein wesentliches Bild von TDD mit anderen zu teilen.

Was ist TDD?

Entwurfs- / Analysetechnik, keine Testtechnik

--Wert

Was ist inkrementelles Design?

――Um etwas Wertvolles so effizient wie möglich zu machen ――Wenn Sie das Entwicklungsziel besser verstehen, desto korrekter können Sie Entscheidungen treffen. ――Ich werde mich erst entscheiden, wenn ich die richtige Entscheidung treffen kann, was ich treffen soll ――Wir entwickeln uns schrittweise aus den minimal erforderlichen Funktionen heraus und entwickeln das Design selbst schrittweise weiter

Geeigneter Fall: Agil ・ Ich weiß nicht, was ich machen möchte ・ Das Entwicklungsteam versteht das Entwicklungsziel nicht vollständig ・ Das Entwicklungsziel ist kompliziert und niemand kennt das richtige Design

fließen

--Rot: Schreiben Sie einen Test, der fehlschlägt (Hinzufügen von Funktionen / Hinzufügen von Bedingungen / Reproduktion von Fehlern usw.)

Wenn wir den obigen Zyklus durchlaufen, werden wir schrittweise basierend auf Rhythmus, Vertrauen und Vertrauen entwerfen.

Punkte zu tun

Praktisches Bildbeispiel

Betreff: Berechnung der Bowling-Punktzahl Nutzungsumgebung: --IntelliJ Community-Version

Zuallererst der einfache und einfache Weg

Alle Strumpfbandkoffer

Startlinie

Der erste Test, der hinzugefügt werden muss, besteht darin, einen "Nichtstun-Test" zu schreiben.

Red

Untitled 2.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  @Test
  public void test_all_Garter() {
    var game = new BowlingGame();
    assertThat(game).isNotNull();
  }
}

Green

Klasse hinzufügen Untitled 3.png

public class BowlingGame {

}

Fügen Sie die kleinste Methode hinzu

Red

Machen Sie es zu einem Testfall für alle Wurfstrumpfbänder

Untitled 4.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  @Test
  public void test_all_Garter() {
    var game = new BowlingGame();
+   for(int count = 0; count < 20; count++) {
+     game.recordOneShot(0);
+   }
-   assertThat(game).isNotNull();
+   assertThat(game.getTotalScore()).isEqualTo(0);
  }
}

Green

Untitled 5.png

public class BowlingGame {

+ public void recordOneShot(int pins) {
+ }

+ public int score() {
+   return 0;
+ }
}

Fall, in dem nur ein Stift niedergeschlagen wird

Red Untitled 7.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  // ry

+ @Test
+ public void test_all_one_pin() {
+   var game = new BowlingGame();
+   for (int count = 0; count < 20; count++) {
+     game.recordOneShot(1);
+   }
+   assertThat(game.score()).isEqualTo(20);
+ }
}

Green

Untitled 8.png

public class BowlingGame {

  private int totalScore = 0;

+ public void recordOneShot(int pins) {
+   totalScore += pins;
+ }

+ public int getTotalScore() {
+   return totalScore;
+ }
}

Refactor, wenn es bedrohlich riecht

Ausgelöst durch den "unheimlichen Geruch" des Codes

//Testcode-Refactor (Entfernung von doppeltem Code: Methodenextraktion)
import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

+ private BowlingGame game;
+
+ @BeforeEach
+ public void setup() {
+   game = new BowlingGame();
+ }

  @Test
  public void test_test_all_Garter() {
-   var game = new BowlingGame();
-   for(int count = 0; count < 20; count++) {
-     game.recordOneShot(0);
-   }
+   recordSamePinsManyShot(20, 0);
    assertThat(game.getTotalScore()).isEqualTo(0);
  }

  @Test
  public void test_all_one_pin() {
-   var game = new BowlingGame();
-   for (int count = 0; count < 20; count++) {
-     game.recordOneShot(1);
-   }
+   recordSamePinsManyShot(20, 1);
    assertThat(game.getTotalScore()).isEqualTo(20);
  }

+ private void recordSamePinsManyShot(int shotCount, int pins) {
+   for (int count = 0; count < shotCount; count++) {
+     game.recordOneShot(pins);
+   }
+ }
}

Ein etwas komplizierter Fall: Ersatz (die Anzahl der Stifte für die nächste Runde wird hinzugefügt)

Red

Untitled 9.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_spare() {
+   game.recordOneShot(4);
+   game.recordOneShot(6); //Ersatz 10+5=15
+   game.recordOneShot(5);
+   recordSamePinsManyShot(17, 0);
+   assertThat(game.getTotalScore()).isEqualTo(20);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Denkweise bei Korrekturen

↓ Versuchen Sie zu beheben

public class BowlingGame {

  private int totalScore = 0;
+ private boolean isSpare = false;

  public void recordOneShot(int pins) {
    totalScore += pins;
+   if (isSpare) {
+     totalScore += pins;
+     isSpare = false;
+   }
+   if (totalScore == 10) {
+     isSpare = true;
+   }
  }

  public int getTotalScore() {
    return totalScore;
  }
}

Untitled 10.png

Untitled 11.png

package bowling;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
+ private int beforePins = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
-   if (totalScore == 10) {
+   if (pins + beforePins == 10) {
      isSpare = true;
    }
+   beforePins = pins;
  }

  public int getTotalScore() {
    return totalScore;
  }
}

Testen wir den blinden Fleck der aktuellen Implementierung

Red

Untitled 12.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry
 
+ @Test
+ public void test_not_spare_when_before_and_current_total_10() {
+   game.recordOneShot(2);
+   game.recordOneShot(6);
+   game.recordOneShot(4);
+   game.recordOneShot(7);
+   recordSamePinsManyShot(16, 0);
+   assertThat(game.getTotalScore()).isEqualTo(19);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Green

Untitled 13.png

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;

  public void recordOneShot(int pins) {
    totalScore += pins;
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
-   if (pins + beforePins == 10) {
+   if (shotCount == 2 && pins + beforePins == 10) {
      isSpare = true;
    }

    beforePins = pins;
+   shotCount = shotCount == 1 ? 2 : 1;
  }

  public int getTotalScore() {
    return totalScore;
  }
}

5. Komplexer Testfall: Strike / Continuous Strike

Streik

Red Untitled 14.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_strike() {
+   game.recordOneShot(10);
+   game.recordOneShot(3);
+   game.recordOneShot(4);
+   game.recordOneShot(2);
+   recordSamePinsManyShot(15, 0);
+   assertThat(game.getTotalScore()).isEqualTo(26);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

--Fest

Green Untitled 15.png

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
+ private int strikeAddScoreCount = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
    if (shotCount == 2 && pins + beforePins == 10) {
      isSpare = true;
    }

+   if (strikeAddScoreCount > 0) {
+     totalScore += pins;
+     strikeAddScoreCount -= 1;
+   }
+   if (pins == 10) {
+     strikeAddScoreCount = 2;
+   }

    beforePins = pins;
    shotCount = shotCount == 1 ? 2 : 1;

  }

  public int getTotalScore() {
    return totalScore;
  }
}

Regelmäßiges Refactoring

Methodenextraktion


package bowling;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
-   if (isSpare) {
-     totalScore += pins;
-     isSpare = false;
-   }
-   if (shotCount == 2 && pins + beforePins == 10) {
-     isSpare = true;
-   }
-
-   if (strikeAddScoreCount > 0) {
-     totalScore += pins;
-     strikeAddScoreCount -= 1;
-   }
-   if (pins == 10) {
-     strikeAddScoreCount = 2;
-   }

+   calcSpareAddScore(pins);
+   calcStrikeAddScore(pins);
    beforePins = pins;
    shotCount = shotCount == 1 ? 2 : 1;
  }

+ public int getTotalScore() {
+   return totalScore;
+ }
+
+ private void calcSpareAddScore(int pins) {
+   if (isSpare) {
+     totalScore += pins;
+     isSpare = false;
+   }
+   if (shotCount == 2 && pins + beforePins == 10) {
+     isSpare = true;
+   }
+ }
+
+ private void calcStrikeAddScore(int pins) {
+   if (strikeAddScoreCount > 0) {
+     totalScore += pins;
+     strikeAddScoreCount -= 1;
+   }
+   if (pins == 10) {
+     strikeAddScoreCount = 2;
+   }
+ }
}

2 aufeinanderfolgende Streiks

Red Untitled 17.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_strike_double() {
+   game.recordOneShot(10);
+   game.recordOneShot(10);
+   game.recordOneShot(4);
+   game.recordOneShot(2);
+   recordSamePinsManyShot(14, 0);
+   assertThat(game.getTotalScore()).isEqualTo(46);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Green Untitled 18.png


public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;
+ private int doubleAddScoreCount = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    beforePins = pins;
    shotCount = shotCount == 1 ? 2 : 1;
  }

  public int getTotalScore() {
    return totalScore;
  }

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
    if (shotCount == 2 && pins + beforePins == 10) {
      isSpare = true;
    }
  }

  private void calcStrikeAddScore(int pins) {
    if (strikeAddScoreCount > 0) {
      totalScore += pins;
      strikeAddScoreCount -= 1;
    }
+   if (doubleAddScoreCount > 0) {
+     totalScore += pins;
+     doubleAddScoreCount -= 1;
+   }
    if (pins == 10) {
+     if (strikeAddScoreCount == 0) {
        strikeAddScoreCount = 2;
+     } else {
+       doubleAddScoreCount = 2;
+     }
    }
  }
}

Testfälle für 3 aufeinanderfolgende Streiks hinzugefügt

Green Untitled 19.png


import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_strike_turkey() {
+   game.recordOneShot(10);
+   game.recordOneShot(10);
+   game.recordOneShot(10);
+   game.recordOneShot(4);
+   game.recordOneShot(2);
+   recordSamePinsManyShot(12, 0);
+   assertThat(game.getTotalScore()).isEqualTo(76);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Komplexer Fall (Fortsetzung): Kombinierter Streik und Ersatz

1 Schlag & 1 Ersatz

Red Untitled 20.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_strike_and_spare() {
+   game.recordOneShot(10);
+   game.recordOneShot(6);
+   game.recordOneShot(4);
+   game.recordOneShot(2);
+   recordSamePinsManyShot(15, 0);
+   assertThat(game.getTotalScore()).isEqualTo(34);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Green Untitled 21.png

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    beforePins = pins;
-   shotCount = shotCount == 1 ? 2 : 1;
+   shotCount = shotCount == 1 && strikeAddScoreCount < 2 ? 2 : 1;
  }

  public int getTotalScore() {
    return totalScore;
  }

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
    if (shotCount == 2 && pins + beforePins == 10) {
      isSpare = true;
    }
  }

  private void calcStrikeAddScore(int pins) {
    if (strikeAddScoreCount > 0) {
      totalScore += pins;
      strikeAddScoreCount -= 1;
    }
    if (doubleAddScoreCount > 0) {
      totalScore += pins;
      doubleAddScoreCount -= 1;
    }
    if (pins == 10) {
      if (strikeAddScoreCount == 0) {
        strikeAddScoreCount = 2;
      } else {
        doubleAddScoreCount = 2;
      }
    }
  }
}

2 aufeinanderfolgende Schläge + Ersatz

Red Untitled 22.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_strike_double_and_spare() {
+   game.recordOneShot(10);
+   game.recordOneShot(10);
+   game.recordOneShot(6);
+   game.recordOneShot(4);
+   game.recordOneShot(2);
+   recordSamePinsManyShot(13, 0);
+   assertThat(game.getTotalScore()).isEqualTo(26+20+12+2);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Green Untitled 23.png

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    beforePins = pins;
-   shotCount = shotCount == 1 && strikeAddScoreCount < 2 ? 2 : 1;
+   shotCount = shotCount == 1 && strikeAddScoreCount < 2 && doubleAddScoreCount < 2 ? 2 : 1;
  }

  public int getTotalScore() {
    return totalScore;
  }

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
    if (shotCount == 2 && pins + beforePins == 10) {
      isSpare = true;
    }
  }

  private void calcStrikeAddScore(int pins) {
    if (strikeAddScoreCount > 0) {
      totalScore += pins;
      strikeAddScoreCount -= 1;
    }
    if (doubleAddScoreCount > 0) {
      totalScore += pins;
      doubleAddScoreCount -= 1;
    }
    if (pins == 10) {
      if (strikeAddScoreCount == 0) {
        strikeAddScoreCount = 2;
      } else {
        doubleAddScoreCount = 2;
      }
    }
  }
}

Refactor (Methodenextraktion)

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;

  public void recordOneShot(int pins) {
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    beforePins = pins;
    shotCount = shotCount == 1 && strikeAddScoreCount < 2 && doubleAddScoreCount < 2 ? 2 : 1;
  }

  public int getTotalScore() {
    return totalScore;
  }

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
    checkSpare(pins);
  }

  private void checkSpare(int pins) {
    if (shotCount == 2 && pins + beforePins == 10) {
      isSpare = true;
    }
  }

  private void calcStrikeAddScore(int pins) {
-   if (strikeAddScoreCount > 0) {
-     totalScore += pins;
-     strikeAddScoreCount -= 1;
-   }
-   if (doubleAddScoreCount > 0) {
-     totalScore += pins;
-     doubleAddScoreCount -= 1;
-   }
-   if (pins == 10) {
-     if (strikeAddScoreCount == 0) {
-       strikeAddScoreCount = 2;
-     } else {
-       doubleAddScoreCount = 2;
-     }
-   }
+   addStrikeScore(pins);
+   addDoubleScore(pins);
+   if (isStrike(pins)) {
+     recognizeStrikeAddCount();
+   }
  }

+ private void addStrikeScore(int pins) {
+  if (strikeAddScoreCount > 0) {
+     totalScore += pins;
+     strikeAddScoreCount -= 1;
+   }
+ }
+
+ private void addDoubleScore(int pins) {
+   if (doubleAddScoreCount > 0) {
+     totalScore += pins;
+     doubleAddScoreCount -= 1;
+   }
+ }
+
+ private boolean isStrike(int pins) {
+   return pins == 10;
+ }
+
+ private void recognizeStrikeAddCount() {
+   if (strikeAddScoreCount == 0) {
+     strikeAddScoreCount = 2;
+   } else {
+     doubleAddScoreCount = 2;
+   }
+ }
}

Holen Sie sich Punkte für jeden Frame

Red Untitled 24.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_one_frame_score_when_all_garter() {
+   recordSamePinsManyShot(20, 0);
+   assertThat(game.getFrameScore(1)).isEqualTo(0);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Green Untitled 25.png

public BowlingGame {

  // ry

+ public int getFrameScore(int frameNum) {
+   return 0;
+ }
}

Überprüfen Sie das statische Design, wenn Sie eine Pattsituation verspüren

――Wenn Sie versuchen, einen Testfall hinzuzufügen, der berechnet werden muss ... Wird er bisher wiederholt?

Rahmenklasse eingeführt

public class Frame {

  public void recordOneShot(int pins) {
  }

  public int getScore(int frameNum) {
    return 0;
  }
}

Wenn nur 1 Pin aller Würfe besiegt ist

Red

Untitled 27.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  @Test
  public void test_one_frame_score_when_all_one_pin() {
    frame.recordOneShot(1);
    assertThat(frame.getScore(1)).isEqualTo(1);
  }
}

Green Untitled 28.png

public class Frame {

  private int score = 0;
  
  public void recordOneShot(int pins) {
+   score += pins;
  }

  public int getScore(int frameNum) {
-   return 0;
+   return score;
  }
}

In Bowling Game eingebauter Rahmen

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
+ private Frame frame = new Frame();

  // ry

+ public int getFrameScore(int frameNum) {
+   return frame.getScore(frameNum);
+ }

  // ry

}
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_one_frame_score_when_all_garter() {
+   recordSamePinsManyShot(20, 0);
+   assertThat(game.getFrameScore(1)).isEqualTo(0);
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Untitled 29.png

In Bowling Game 2 eingebauter Rahmen (Aufgabentrennung)

--Statische Entwurfsprüfung: Delegieren Sie Folgendes an die Frame-Klasse

Beurteilung der Rahmenvervollständigung

Red

Untitled 30.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

+ @Test
+ public void test_frame_finish_two_shot() {
+   frame.recordOneShot(1);
+   assertThat(frame.isFinished()).isFalse();
+   frame.recordOneShot(1);
+   assertThat(frame.isFinished()).isTrue();
+ }
}

Green Untitled 31.png

package bowling;

public class Frame {

  private int score = 0;
+ private int shotCount = 0;

  public void recordOneShot(int pins) {
    score += pins;
+   shotCount++;
  }

  public int getScore(int frameNum) {
    return score;
  }

+ public boolean isFinished() {
+   return shotCount >= 2;
+ }
}

Rahmenvervollständigungsurteil (Streik)

Red Untitled 32.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

+ @Test
+ public void test_frame_finish_strike() {
+   var frame = new Frame();
+   frame.recordOneShot(10);
+   assertThat(frame.isFinished()).isTrue();
+ }
}

Green Untitled 33.png

public class Frame {

  private int score = 0;
  private int shotCount = 0;

  public void recordOneShot(int pins) {
    score += pins;
    shotCount++;
  }

  public int getScore(int frameNum) {
    return score;
  }

  public boolean isFinished() {
-   return shotCount >= 2;
+   return shotCount >= 2 || score >= 10;
  }
}

Eingebautes Rahmenurteil in Bowling Game

2 Punkte für alle Frames mit 1 Pin für alle Würfe

Red Untitled 34.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class BowlingGameTest {

  private BowlingGame game;

  @BeforeEach
  public void setup() {
    game = new BowlingGame();
  }

  // ry

+ @Test
+ public void test_one_frame_score_is_2_when_all_one_pin() {
+   recordSamePinsManyShot(20, 1);
+   for (int frameNum = 0; frameNum < 10; frameNum++) {
+     assertThat(game.getFrameScore(frameNum + 1)).isEqualTo(2);
+   }
+ }

  private void recordSamePinsManyShot(int shotCount, int pins) {
    for (int count = 0; count < shotCount; count++) {
      game.recordOneShot(pins);
    }
  }
}

Green Untitled 35.png

import java.util.LinkedList;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int beforePins = 0;
  private int shotCount = 1;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
- private Frame frame = new Frame();
+ private final LinkedList<Frame> frames = new LinkedList<>() {
+   {
+     add(new Frame());
+   }
+ };

  public void recordOneShot(int pins) {
+   var frame = frames.getLast();
+   frame.recordOneShot(pins);
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    beforePins = pins;
    shotCount = shotCount == 1 && strikeAddScoreCount < 2 && doubleAddScoreCount < 2 ? 2 : 1;
+   if (frame.isFinished()) {
+     frames.add(new Frame());
+   }
  }

  public int getTotalScore() {
    return totalScore;
  }

+ public int getFrameScore(int frameNum) {
+   return frames.get(frameNum - 1).getScore();
+ }

  // ry

}

Ergebnisurteil werfen

schonen

Red Untitled 36.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;

public class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

+ @Test
+ public void test_spare_when_defect_10_pins_in_second_shot_of_frame() {
+   frame.recordOneShot(5);
+   assertThat(frame.isSpare()).isFalse();
+   frame.recordOneShot(5);
+   assertThat(frame.isSpare()).isTrue();
+ }
}

Green Untitled 37.png

public class Frame {

  private int score = 0;
  private int shotCount = 0;

  public void recordOneShot(int pins) {
    score += pins;
    shotCount++;
  }

  public int getScore() {
    return score;
  }

  public boolean isFinished() {
    return shotCount >= 2 || score >= 10;
  }

+ public boolean isSpare() {
+   return score == 10 && shotCount >= 2;
+ }

}
Streik

Red Untitled 38.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  //ry

+ @Test
+ public void test_strike_when_defect_10_pins_in_first_shot_of_frame() {
+   assertThat(frame.isStrike()).isFalse();
+   frame.recordOneShot(10);
+   assertThat(frame.isStrike()).isTrue();
+ }
}

Green Untitled 39.png

public class Frame {

  private int score = 0;
  private int shotCount = 0;

  public void recordOneShot(int pins) {
    score += pins;
    shotCount++;
  }

  public int getScore() {
    return score;
  }

  public boolean isFinished() {
    return shotCount >= 2 || score >= 10;
  }

  public boolean isSpare() {
    return score == 10 && shotCount >= 2;
  }

+ public boolean isStrike() {
+   return score == 10 && shotCount == 1;
+ }
}

Integrieren Sie das Werfen in Bowling Game

schonen

Untitled 40.png

import java.util.LinkedList;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
  private final LinkedList<Frame> frames = new LinkedList<>() {
    {
      add(new Frame());
    }
  };

  public void recordOneShot(int pins) {
    var frame = frames.getLast();
    frame.recordOneShot(pins);
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    if (frame.isFinished()) {
      frames.add(new Frame());
    }
  }

  public int getTotalScore() {
    return totalScore;
  }

  public int getFrameScore(int frameNum) {
    return frames.get(frameNum - 1).getScore();
  }

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
-   checkSpare(pins);
+   if (frames.getLast().isSpare()) {
+     isSpare = true;
+   }
  }

- private void checkSpare(int pins) {
-   if (shotCount == 2 && pins + beforePins == 10) {
-     isSpare = true;
-   }
- }

  private void calcStrikeAddScore(int pins) {
    addStrikeScore(pins);
    addDoubleScore(pins);
    if (isStrike(pins)) {
      recognizeStrikeAddCount();
    }
  }

  private void addStrikeScore(int pins) {
    if (strikeAddScoreCount > 0) {
      totalScore += pins;
      strikeAddScoreCount -= 1;
    }
  }

  private void addDoubleScore(int pins) {
    if (doubleAddScoreCount > 0) {
      totalScore += pins;
      doubleAddScoreCount -= 1;
    }
  }

  private boolean isStrike(int pins) {
    return pins == 10;
  }

  private void recognizeStrikeAddCount() {
    if (strikeAddScoreCount == 0) {
      strikeAddScoreCount = 2;
    } else {
      doubleAddScoreCount = 2;
    }
  }
}
Streik

Untitled 41.png

import java.util.LinkedList;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
  private final LinkedList<Frame> frames = new LinkedList<>() {
    {
      add(new Frame());
    }
  };

  public void recordOneShot(int pins) {
    var frame = frames.getLast();
    frame.recordOneShot(pins);
    totalScore += pins;
    calcSpareAddScore(pins);
    calcStrikeAddScore(pins);
    if (frame.isFinished()) {
      frames.add(new Frame());
    }
  }

  public int getTotalScore() {
    return totalScore;
  }

  public int getFrameScore(int frameNum) {
    return frames.get(frameNum - 1).getScore();
  }

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
    }
    if (frames.getLast().isSpare()) {
      isSpare = true;
    }
  }

  private void calcStrikeAddScore(int pins) {
    addStrikeScore(pins);
    addDoubleScore(pins);
-   if (isStrike(pins)) {
+   if (frames.getLast().isStrike()) {
      recognizeStrikeAddCount();
    }
  }

  private void addStrikeScore(int pins) {
    if (strikeAddScoreCount > 0) {
      totalScore += pins;
      strikeAddScoreCount -= 1;
    }
  }

  private void addDoubleScore(int pins) {
    if (doubleAddScoreCount > 0) {
      totalScore += pins;
      doubleAddScoreCount -= 1;
    }
  }

  private void recognizeStrikeAddCount() {
    if (strikeAddScoreCount == 0) {
      strikeAddScoreCount = 2;
    } else {
      doubleAddScoreCount = 2;
    }
  }
}

(Bonus) Punktzahl Addition Urteil / Rekord nach Streik / Ersatz

Zum Rahmen wechseln

Red Untitled 42.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

+ @Test
+ public void test_spare_add_bonus_score() {
+   frame.recordOneShot(5);
+   frame.recordOneShot(5);
+   frame.addBonusScore(5);
+   assertThat(frame.getScore()).isEqualTo(15);
+ }
}

Green Untitled 43.png

package bowling;

public class Frame {

  private int score = 0;
  private int shotCount = 0;

  public void recordOneShot(int pins) {
    score += pins;
    shotCount++;
  }

  public int getScore() {
    return score;
  }

  public boolean isFinished() {
    return shotCount >= 2 || score >= 10;
  }

  public boolean isSpare() {
    return score == 10 && shotCount >= 2;
  }

  public boolean isStrike() {
    return score == 10 && shotCount == 1;
  }

+ public void addBonusScore(int bonusScore) {
+   score += bonusScore;
+ }
}

Integrieren Sie eine zusätzliche Bewertung / Aufzeichnung der Bonuspunktzahl in das Bowling-Spiel

schonen

Red Untitled 44.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

+ @Test
+ public void test_spare_frame_score_add_next_pins() {
+   game.recordOneShot(4);
+   game.recordOneShot(6);
+   game.recordOneShot(5);
+   assertThat(game.getFrameScore(1)).isEqualTo(15);
+   assertThat(game.getTotalScore()).isEqualTo(20);
+ }
}

Green Untitled 45.png

import java.util.LinkedList;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
+ private Frame spareFrame = null;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
  private final LinkedList<Frame> frames = new LinkedList<>() {
    {
      add(new Frame());
    }
  };

  // ry

  private void calcSpareAddScore(int pins) {
    if (isSpare) {
      totalScore += pins;
      isSpare = false;
+     spareFrame.addBonusScore(pins);
+     spareFrame = null;
    }
    if (frames.getLast().isSpare()) {
      isSpare = true;
+     spareFrame = frames.getLast();
    }
  }

  // ry
}
Streik

Red Untitled 46.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

  @Test
  public void test_strike_frame_score_add_twice_next_pins() {
    game.recordOneShot(10);
    game.recordOneShot(3);
    game.recordOneShot(4);
    game.recordOneShot(2);
    recordSamePinsManyShot(15, 0);
    assertThat(game.getTotalScore()).isEqualTo(26);
    assertThat(game.getFrameScore(1)).isEqualTo(17);
  }
}

Green Untitled 47.png

import java.util.LinkedList;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private Frame spareFrame = null;
+ private Frame strikeFrame = null;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
  private final LinkedList<Frame> frames = new LinkedList<>() {
    {
      add(new Frame());
    }
  };

  // ry

  private void addStrikeScore(int pins) {
    if (strikeAddScoreCount > 0) {
      totalScore += pins;
      strikeAddScoreCount -= 1;
+     strikeFrame.addBonusScore(pins);
    }
  }

  private void addDoubleScore(int pins) {
    if (doubleAddScoreCount > 0) {
      totalScore += pins;
      doubleAddScoreCount -= 1;
    }
  }

  private void recognizeStrikeAddCount() {
    if (strikeAddScoreCount == 0) {
      strikeAddScoreCount = 2;
+     strikeFrame = frames.getLast();
    } else {
      doubleAddScoreCount = 2;
    }
  }
}
Streik (2 aufeinanderfolgende)

Red Untitled 48.png

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FrameTest {

  private Frame frame;

  @BeforeEach
  public void setup() {
    frame = new Frame();
  }

  // ry

+ @Test
+ public void test_strike_double_frame_score() {
+   game.recordOneShot(10);
+   game.recordOneShot(10);
+   game.recordOneShot(4);
+   game.recordOneShot(2);
+   recordSamePinsManyShot(14, 0);
+   assertThat(game.getTotalScore()).isEqualTo(46);
+   assertThat(game.getFrameScore(1)).isEqualTo(24);
+   assertThat(game.getFrameScore(2)).isEqualTo(16);
+ }
}

Green Untitled 49.png

import java.util.LinkedList;

public class BowlingGame {

  private int totalScore = 0;
  private boolean isSpare = false;
  private Frame spareFrame = null;
  private Frame strikeFrame = null;
+ private Frame doubleFrame = null;
  private int strikeAddScoreCount = 0;
  private int doubleAddScoreCount = 0;
  private final LinkedList<Frame> frames = new LinkedList<>() {
    {
      add(new Frame());
    }
  };

  // ry

  private void addDoubleScore(int pins) {
    if (doubleAddScoreCount > 0) {
      totalScore += pins;
      doubleAddScoreCount -= 1;
+     doubleFrame.addBonusScore(pins);
    }
  }

  private void recognizeStrikeAddCount() {
    if (strikeAddScoreCount == 0) {
      strikeAddScoreCount = 2;
      strikeFrame = frames.getLast();
    } else {
      doubleAddScoreCount = 2;
+     doubleFrame = frames.getLast();
    }
  }
}

Fortsetzung aber ausstehend

Verschieben Sie als Nächstes das Urteil von strikeAddScoreCount und doubleAddScoreCount in Frame.

Sogar bis jetzt scheint es, dass ich es mir bis zu einem gewissen Grad vorstellen kann, bis jetzt einmal (erschöpft)

Wesentliches Bild von TDD

Ich weiß es nicht für mein Verständnis.

Abstraktes Bild

Machen Sie zunächst (Entschuldigung für das grobe Bild) bitte das folgende Bild aus dem Bild.

――Der äußerste Kreis unten ist das gesamte Entwicklungsziel, und es gibt mehrere Probleme / Probleme (graue Kreise im Bild unten) = Das Entwicklungsziel ist eine Sammlung (Klumpen) von Problemen / Problemen

image.png

Basierend auf dem oben Gesagten, wenn es darum geht, tatsächlich mit der Entwicklung fortzufahren, wenn das Verständnis des Ziels für diese Masse schlecht ist,

――Ich weiß nicht, womit ich anfangen soll ――Ich weiß nicht, wie ich vorgehen soll

Ich denke, es wird. Auf der anderen Seite TDD Löse in der Reihenfolge von der, die einzeln von außen gelöst werden kann. Auch wenn es auf den ersten Blick ein Umweg war. Im Idealfall kann der kürzeste Weg die Probleme lösen, aber es ist praktisch unmöglich, die Probleme mit dem kürzesten Weg zu lösen, wenn ein innerer Teil noch nicht sichtbar ist. Wenn Sie der Meinung sind, dass dies das kürzeste ist und Sie versuchen, mehrere Probleme gleichzeitig zu lösen, ist dies ziemlich kompliziert und dauert länger. Oft kommt es vor, dass Sie komplizierte Arbeiten ausführen.

Deshalb zerlegen wir es in kleinere Partikel und lösen die Probleme nacheinander.

Indem Sie sich nacheinander entwirren, nähern Sie sich allmählich dem Kern und verbessern Ihr Verständnis des Themas. Wenn Sie den Kern oder ein Problem in der Nähe erreichen, wird sich Ihr Verständnis des Themas vertiefen und Sie können die richtigen Entscheidungen über das Problem treffen (deshalb sollten Sie sich erst entscheiden, wenn Sie die richtige Entscheidung treffen können. Selbst wenn Sie eine vorläufige Entscheidung in einem Zustand treffen, in dem Sie dies noch nicht tun können, handelt es sich im Allgemeinen um einen zusätzlichen Build.

Bei der tatsächlichen Implementierung denke ich, dass es ** definiert / deklariert, welches Problem durch Schreiben eines Testfalls ** gelöst werden soll.

Bild des TDD-Ansatzes

Basierend auf dem oben Gesagten ist TDD unter Berücksichtigung des TDD-Ansatzes

** Setzen Sie sich kleine Ziele (Ziele, die angestrebt werden sollen, und zu lösende Probleme), indem Sie Testfälle schreiben, und konzentrieren Sie sich auf nur ein Ziel vor Ihnen. Dies wird wiederholt. ** **.

** Indem Sie es separat tun, auch statisches Design und dynamisches Design **

--Statisches Design ≒ Berücksichtigen Sie nur die Logik / den Algorithmus (wenn Rot → Grün). --Dynamisches Design ≒ Berücksichtigen Sie nur das Klassen- / Schnittstellendesign (zum Zeitpunkt von Refactor).

Wenn Sie eines ausführen, können Sie sich auf das andere konzentrieren. Durch Drehen des Rot / Grün / Refactor-Zyklus können Sie das Design / die Implementierung verfeinern und dabei die Qualität des Designs in gewissem Maße beibehalten (abhängig von der Kompetenz des Entwicklers). Ich denke.

Da Refactor auf der Sicherheit und Zuverlässigkeit basiert, die mit den folgenden Sicherheiten erzielt werden können, ist es außerdem möglich, sich auf die Arbeit des Denkens über dynamisches Design zu konzentrieren.

Ich habe verstanden. das ist alles

Referenz

[Buch: Einführung in die testgetriebene TDD-Entwicklung ab sofort](https://www.amazon.co.jp/%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89%E3 % 81% AF% E3% 81% 98% E3% 82% 81% E3% 82% 8BTDD-% E3% 83% 86% E3% 82% B9% E3% 83% 88% E9% A7% 86% E5% 8B% 95% E9% 96% 8B% E7% 99% BA% E5% 85% A5% E9% 96% 80-ThinkIT-Books-% E5% 90% 89% E8% B0% B7-ebook / dp / B00VFQ7WCM / ref = cm_cr_arp_d_product_top? ie = UTF8)

[Buch: Test Driven Development](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95 % E9% 96% 8B% E7% 99% BA-% EF% BC% AB% EF% BD% 85% EF% BD% 8E% EF% BD% 94% EF% BC% A2% EF% BD% 85% EF% BD% 83% EF% BD% 8B-ebook / dp / B077D2L69C / ref = sr_1_1? __Mk_ja_JP =% E3% 82% AB% E3% 82% BF% E3% 82% AB% E3% 83% 8A & dchild = 1 & Schlüsselwörter =% E3% 83% 86% E3% 82% B9% E3% 83% 88% E9% A7% 86% E5% 8B% 95% E9% 96% 8B% E7% 99% BA & qid = 1605338667 & s = digitaler Text & sr = 1-1)

Recommended Posts

Halten Sie das praktische Bild und das wesentliche Bild gedrückt, um TDD anzugehen
Android App, die Bilder aus der Galerie auswählt und anzeigt
So schränken Sie das Bildformat in der Galerie unter Android ein und wählen und importieren Sie dann mehrere Bilder
Wie man die Zehner und Einsen findet