Cet article est écrit pour s'attaquer au TDD et pour partager avec d'autres une image essentielle du TDD.
Technique de conception / analyse, pas technique de test
--Valeur
――Pour rendre quelque chose de précieux aussi efficacement que possible «Parce que plus vous comprenez l'objectif de développement, plus vous pouvez prendre de bonnes décisions. ――Je ne déciderai pas tant que je n'aurai pas pris la bonne décision sur ce qu'il faut faire ――Nous nous développons progressivement à partir des fonctions minimales requises et faisons évoluer progressivement la conception elle-même
Cas approprié: Agile ・ Je ne sais pas ce que je veux faire ・ L'équipe de développement ne comprend pas entièrement l'objectif de développement ・ L'objectif de développement est compliqué et personne ne connaît la bonne conception
--Rouge: Ecrire un test qui échoue (ajout de fonctions / ajout de conditions / reproduction de bogues etc.)
En passant par le cycle ci-dessus, nous allons concevoir progressivement en fonction du rythme, de la confiance et de la confiance.
Sujet: calcul du score de bowling environnement d'utilisation:
Le premier test à ajouter est d'écrire un test "ne rien faire"
Red
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
Ajouter une classe
public class BowlingGame {
}
Red
Faites-en un cas de test pour toutes les jarretières de lancer
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
public class BowlingGame {
+ public void recordOneShot(int pins) {
+ }
+ public int score() {
+ return 0;
+ }
}
Red
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
public class BowlingGame {
private int totalScore = 0;
+ public void recordOneShot(int pins) {
+ totalScore += pins;
+ }
+ public int getTotalScore() {
+ return totalScore;
+ }
}
Déclenché par «l'odeur sinistre» du code
--Code en double
//Refactor de code de test (suppression de code en double: extraction de méthode)
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);
+ }
+ }
}
Red
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); //Réserve 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);
}
}
}
Réfléchissez à la façon de réparer
Pensez à la cause → Parce que je ne me souviens pas de l'état de lancement précédent
Envisagez une solution de contournement → Préparez un drapeau de rechange
Pensez à la procédure
Ajout d'un drapeau de rechange
Le total des points est de 10 points → Le drapeau est activé, si le drapeau est activé, ajoutez
↓ Essayez de réparer
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;
}
}
--Fixé pour réussir si le test existant échoue --Cause → Parce que le drapeau était activé lorsque le score total était de 10.
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;
}
}
Red
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
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;
}
}
Red
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);
}
}
}
--Fixé --Cause: la grève ne peut pas être déterminée
Green
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;
}
}
Extraction de méthode
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;
+ }
+ }
}
Red
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
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;
+ }
}
}
}
Green
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);
}
}
}
Red
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);
}
}
}
--Cause: shotCount ne revient pas à 1 après l'attaque
Green
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;
}
}
}
}
Red
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);
}
}
}
--Cause: shotCount ne revient pas à 1 même après 2 frappes consécutives
Green
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;
}
}
}
}
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;
+ }
+ }
}
Red
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
public BowlingGame {
// ry
+ public int getFrameScore(int frameNum) {
+ return 0;
+ }
}
――Lorsque vous essayez d'ajouter un cas de test qui doit être calculé ... Sera-t-il répété jusqu'à présent?
Classe de trame introduite
public class Frame {
public void recordOneShot(int pins) {
}
public int getScore(int frameNum) {
return 0;
}
}
Red
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
public class Frame {
private int score = 0;
public void recordOneShot(int pins) {
+ score += pins;
}
public int getScore(int frameNum) {
- return 0;
+ return score;
}
}
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);
}
}
}
MECE (Mutuellement Exclusif et Collectivement Exhaustif): Une vue d'ensemble de la conception de la classe du point de vue de l'absence de duplication et d'aucune omission
Refactoriser en se concentrant uniquement sur les fonctions qui sont claires pour le moment
Red
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
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;
+ }
}
Red
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
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;
}
}
Red
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
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
}
Red
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
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;
+ }
}
Red
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
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;
+ }
}
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;
}
}
}
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;
}
}
}
Red
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
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;
+ }
}
Red
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
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
}
Red
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
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;
}
}
}
Red
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
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();
}
}
}
Ensuite, déplacez le jugement par strikeAddScoreCount et doubleAddScoreCount vers Frame.
Même jusqu'à présent, il semble que je peux l'imaginer dans une certaine mesure, donc une fois pour l'instant (épuisé)
Je ne sais pas pour ma compréhension.
Tout d'abord (désolé pour l'image approximative), veuillez créer l'image suivante à partir de l'image.
―― Le cercle le plus à l'extérieur ci-dessous est la cible de développement entière, et il y a plusieurs problèmes / problèmes (cercles gris dans l'image ci-dessous) = La cible de développement est un ensemble (ensemble) de problèmes / problèmes
Sur la base de ce qui précède, lorsqu'il s'agit de procéder réellement au développement, si la compréhension de la cible est mauvaise, pour cette masse,
――Je ne sais pas par quoi commencer ――Je ne sais pas comment procéder
Je pense que ce sera. D'autre part, TDD Résolvez dans l'ordre de celui qui peut être résolu un par un de l'extérieur. Même si c'était un détour à première vue. Idéalement, l'itinéraire le plus court peut résoudre les problèmes, mais il est pratiquement impossible de résoudre les problèmes avec l'itinéraire le plus court avec certaines parties internes qui ne sont pas encore visibles. De plus, si vous pensez que c'est le plus court et essayez de résoudre plusieurs problèmes en même temps, ce sera compliqué et cela prendra plus de temps, et il vous arrivera souvent de faire un travail compliqué.
C'est pourquoi nous le décomposons en particules plus petites et résolvons les problèmes un par un.
En démêlant un à un, vous vous rapprocherez progressivement du cœur et progresserez dans votre compréhension du sujet. Au moment où vous atteindrez le cœur ou un problème proche, votre compréhension du sujet s'approfondira et vous serez en mesure de prendre les bonnes décisions concernant le problème (c'est pourquoi vous ne devriez pas décider avant d'avoir pris la bonne décision. Même si vous prenez une décision provisoire dans un état où vous ne pouvez pas encore le faire, ce sera généralement une version supplémentaire).
Lors de sa mise en œuvre, je pense que c'est ** définir / déclarer le problème à résoudre en écrivant un cas de test **.
Sur la base de ce qui précède, compte tenu de l'approche TDD, TDD est
** Fixez-vous des objectifs de petite taille (objectifs à viser et problèmes à résoudre) en écrivant des cas de test, et concentrez-vous sur un seul objectif devant vous. Cela se répète. ** **
** En le faisant séparément, même conception statique et conception dynamique **
Lorsque vous en faites un, vous pouvez vous concentrer sur l'autre, et en tournant le cycle Rouge / Vert / Refactor, vous pouvez affiner la conception / mise en œuvre tout en conservant dans une certaine mesure la qualité de la conception (en fonction de la compétence du développeur). Je pense.
De plus, comme Refactor est basé sur la sécurité et la fiabilité qui peuvent être obtenues avec les éléments suivants en garantie, il est possible de se concentrer sur le travail de réflexion sur la conception dynamique.
--Compréhension / mise en œuvre de la logique nécessaire pour atteindre l'objectif
J'ai compris. c'est tout
[Livre: Introduction au développement piloté par les tests TDD à partir de maintenant](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)
[Livre: 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 & mots-clés =% E3% 83% 86% E3% 82% B9% E3% 83% 88% E9% A7% 86% E5% 8B% 95% E9% 96% 8B% E7% 99% BA & qid = 1605338667 & s = digital-text & sr = 1-1)
Recommended Posts