diff --git a/src/main/java/bowling/App.java b/src/main/java/bowling/App.java
new file mode 100644
index 0000000000..5a3f7de79e
--- /dev/null
+++ b/src/main/java/bowling/App.java
@@ -0,0 +1,22 @@
+package bowling;
+
+import bowling.domain.Hit;
+import bowling.domain.Name;
+import bowling.domain.Round;
+import bowling.view.InputView;
+import bowling.view.ResultView;
+
+public class App {
+
+ public static void main(String[] args) {
+ Name name = InputView.inputName();
+
+ Round round = new Round();
+ ResultView.printRound(name, round);
+ while (!round.isEnd()) {
+ Hit hit = InputView.inputPins(round.getCurrentFrameNumber());
+ round.hit(hit);
+ ResultView.printRound(name, round);
+ }
+ }
+}
diff --git a/src/main/java/bowling/domain/Frame.java b/src/main/java/bowling/domain/Frame.java
new file mode 100644
index 0000000000..c0550618e1
--- /dev/null
+++ b/src/main/java/bowling/domain/Frame.java
@@ -0,0 +1,16 @@
+package bowling.domain;
+
+public interface Frame {
+
+ void play(Hit hit);
+
+ FrameStatus getFirstStatus();
+ FrameStatus getSecondStatus();
+ FrameStatus getThirdStatus();
+
+ Hit getFirstHit();
+ Hit getSecondHit();
+ Hit getThirdHit();
+
+ boolean isEnd();
+}
diff --git a/src/main/java/bowling/domain/FrameStatus.java b/src/main/java/bowling/domain/FrameStatus.java
new file mode 100644
index 0000000000..18608e195e
--- /dev/null
+++ b/src/main/java/bowling/domain/FrameStatus.java
@@ -0,0 +1,11 @@
+package bowling.domain;
+
+public enum FrameStatus {
+ BEFORE,
+ PLAYING,
+ SKIP,
+ STRIKE,
+ SPARE,
+ MISS,
+ GUTTER;
+}
diff --git a/src/main/java/bowling/domain/Hit.java b/src/main/java/bowling/domain/Hit.java
new file mode 100644
index 0000000000..4d568b99b4
--- /dev/null
+++ b/src/main/java/bowling/domain/Hit.java
@@ -0,0 +1,43 @@
+package bowling.domain;
+
+public class Hit {
+ public static final int MIN = 0;
+ public static final int MAX = 10;
+ private final int hit;
+
+
+ public Hit(int hit) {
+ validate(hit);
+ this.hit = hit;
+ }
+
+ private void validate(int hit) {
+ if (hit < MIN || hit > MAX) {
+ throw new IllegalArgumentException("범위를 벗어나는 점수가 입력되었습니다.");
+ }
+ }
+
+ public Hit plus(Hit target) {
+ return new Hit(hit + target.hit);
+ }
+
+ public boolean isMin() {
+ return hit == MIN;
+ }
+
+ public boolean isMax() {
+ return hit == MAX;
+ }
+
+ public int getScore() {
+ return hit;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Hit)) {
+ return false;
+ }
+ return hit == ((Hit) obj).hit;
+ }
+}
diff --git a/src/main/java/bowling/domain/LastFrame.java b/src/main/java/bowling/domain/LastFrame.java
new file mode 100644
index 0000000000..b2a516026a
--- /dev/null
+++ b/src/main/java/bowling/domain/LastFrame.java
@@ -0,0 +1,122 @@
+package bowling.domain;
+
+public class LastFrame implements Frame {
+ private Hit first;
+ private Hit second;
+ private Hit third;
+
+ @Override
+ public void play(Hit hit) {
+ if (getFirstStatus() == FrameStatus.BEFORE) {
+ firstThrow(hit);
+ return;
+ }
+ if (getSecondStatus() == FrameStatus.BEFORE) {
+ secondThrow(hit);
+ return;
+ }
+ thirdThrow(hit);
+ }
+
+ private void firstThrow(Hit hit) {
+ this.first = hit;
+ }
+
+ private void secondThrow(Hit hit) {
+ this.second = hit;
+ }
+
+ private void thirdThrow(Hit hit) {
+ this.third = hit;
+ }
+
+ @Override
+ public FrameStatus getFirstStatus() {
+ return getNormalStatus(first);
+ }
+
+ @Override
+ public FrameStatus getSecondStatus() {
+ if (first == null || second == null) {
+ return FrameStatus.BEFORE;
+ }
+ if (first.isMax()) {
+ return getNormalStatus(second);
+ }
+ Hit sum = first.plus(second);
+ if (sum.isMax()) {
+ return FrameStatus.SPARE;
+ }
+ if (second.isMin()) {
+ return FrameStatus.GUTTER;
+ }
+ return FrameStatus.MISS;
+ }
+
+ @Override
+ public FrameStatus getThirdStatus() {
+ if (first == null || second == null || third == null) {
+ return FrameStatus.BEFORE;
+ }
+ if (!canPlayThird()) {
+ return FrameStatus.SKIP;
+ }
+ if (third.isMax()) {
+ return FrameStatus.STRIKE;
+ }
+ if (third.isMin()) {
+ return FrameStatus.GUTTER;
+ }
+ if (second.isMax()) {
+ return FrameStatus.MISS;
+ }
+ Hit sum = second.plus(third);
+ if (sum.isMax()) {
+ return FrameStatus.SPARE;
+ }
+ return FrameStatus.MISS;
+ }
+
+ private FrameStatus getNormalStatus(Hit hit) {
+ if (hit == null) {
+ return FrameStatus.BEFORE;
+ }
+ if (hit.isMax()) {
+ return FrameStatus.STRIKE;
+ }
+ if (hit.isMin()) {
+ return FrameStatus.GUTTER;
+ }
+ return FrameStatus.MISS;
+ }
+
+ @Override
+ public Hit getFirstHit() {
+ return first;
+ }
+
+ @Override
+ public Hit getSecondHit() {
+ return second;
+ }
+
+ @Override
+ public Hit getThirdHit() {
+ return third;
+ }
+
+ @Override
+ public boolean isEnd() {
+ if (first == null || second == null) {
+ return false;
+ }
+ if (third != null) {
+ return true;
+ }
+ return !canPlayThird();
+ }
+
+ private boolean canPlayThird() {
+ return getFirstStatus() == FrameStatus.STRIKE || getSecondStatus() == FrameStatus.SPARE;
+ }
+}
diff --git a/src/main/java/bowling/domain/Name.java b/src/main/java/bowling/domain/Name.java
new file mode 100644
index 0000000000..c48ae4a40f
--- /dev/null
+++ b/src/main/java/bowling/domain/Name.java
@@ -0,0 +1,21 @@
+package bowling.domain;
+
+public class Name {
+ private final String name;
+
+
+ public Name(String name) {
+ validate(name);
+ this.name = name;
+ }
+
+ private void validate(String name) {
+ if (name.length() != 3) {
+ throw new IllegalArgumentException("이름은 3글자로 입력되어야 합니다");
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/bowling/domain/NormalFrame.java b/src/main/java/bowling/domain/NormalFrame.java
new file mode 100644
index 0000000000..6812863df9
--- /dev/null
+++ b/src/main/java/bowling/domain/NormalFrame.java
@@ -0,0 +1,83 @@
+package bowling.domain;
+
+public class NormalFrame implements Frame {
+ private Hit first;
+ private Hit second;
+
+ @Override
+ public void play(Hit hit) {
+ if (getFirstStatus() == FrameStatus.BEFORE) {
+ firstThrow(hit);
+ return;
+ }
+ secondThrow(hit);
+ }
+
+ private void firstThrow(Hit hit) {
+ this.first = hit;
+ if (hit.isMax()) {
+ second = new Hit(0);
+ }
+ }
+
+ private void secondThrow(Hit hit) {
+ this.second = hit;
+ }
+
+ @Override
+ public FrameStatus getFirstStatus() {
+ if (first == null) {
+ return FrameStatus.BEFORE;
+ }
+ if (first.isMax()) {
+ return FrameStatus.STRIKE;
+ }
+ if (first.isMin()) {
+ return FrameStatus.GUTTER;
+ }
+ return FrameStatus.MISS;
+ }
+
+ @Override
+ public FrameStatus getSecondStatus() {
+ if (first == null || second == null) {
+ return FrameStatus.BEFORE;
+ }
+ if (first.isMax()) {
+ return FrameStatus.SKIP;
+ }
+ Hit sum = first.plus(second);
+ if (sum.isMax()) {
+ return FrameStatus.SPARE;
+ }
+ if (second.isMin()) {
+ return FrameStatus.GUTTER;
+ }
+ return FrameStatus.MISS;
+ }
+
+ @Override
+ public FrameStatus getThirdStatus() {
+ return FrameStatus.SKIP;
+ }
+
+ @Override
+ public Hit getFirstHit() {
+ return first;
+ }
+
+ @Override
+ public Hit getSecondHit() {
+ return second;
+ }
+
+ @Override
+ public Hit getThirdHit() {
+ return new Hit(0);
+ }
+
+ @Override
+ public boolean isEnd() {
+ return first != null && second != null;
+ }
+}
diff --git a/src/main/java/bowling/domain/Round.java b/src/main/java/bowling/domain/Round.java
new file mode 100644
index 0000000000..c78659c8d8
--- /dev/null
+++ b/src/main/java/bowling/domain/Round.java
@@ -0,0 +1,50 @@
+package bowling.domain;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class Round {
+ private static final int ROUND_COUNT = 10;
+ private final List frames;
+
+ public Round() {
+ frames = IntStream.range(0, ROUND_COUNT - 1)
+ .mapToObj(i -> new NormalFrame())
+ .collect(Collectors.toList());
+ frames.add(new LastFrame());
+ }
+
+ public void hit(Hit hit) {
+ Frame last = getLastPlayingFrame()
+ .orElseThrow(() -> new IllegalStateException("모든 프레임이 종료되었습니다."));
+ last.play(hit);
+ }
+
+ public boolean isEnd() {
+ Optional last = getLastPlayingFrame();
+ return last.isEmpty();
+ }
+
+ public int getCurrentFrameNumber() {
+ Optional last = getLastPlayingFrame();
+ if (last.isEmpty()) {
+ return ROUND_COUNT;
+ }
+ Frame currentFrame = last.get();
+ return frames.indexOf(currentFrame) + 1;
+
+ }
+
+ private Optional getLastPlayingFrame() {
+ return frames.stream()
+ .filter(frame -> !frame.isEnd())
+ .findFirst();
+ }
+
+ public void forEach(Consumer consumer) {
+ frames.forEach(consumer);
+ }
+}
diff --git a/src/main/java/bowling/view/InputView.java b/src/main/java/bowling/view/InputView.java
new file mode 100644
index 0000000000..6428a712a6
--- /dev/null
+++ b/src/main/java/bowling/view/InputView.java
@@ -0,0 +1,23 @@
+package bowling.view;
+
+import bowling.domain.Name;
+import bowling.domain.Hit;
+
+import java.util.Scanner;
+
+public class InputView {
+ private static final Scanner scanner = new Scanner(System.in);
+
+ public static Name inputName() {
+ System.out.print("플레이어 이름은 (3 english letters)?: ");
+
+ String name = scanner.nextLine();
+ return new Name(name);
+ }
+
+ public static Hit inputPins(int frame) {
+ System.out.printf("%d프레임 투구: ", frame);
+
+ return new Hit(scanner.nextInt());
+ }
+}
diff --git a/src/main/java/bowling/view/ResultView.java b/src/main/java/bowling/view/ResultView.java
new file mode 100644
index 0000000000..56812d8f0a
--- /dev/null
+++ b/src/main/java/bowling/view/ResultView.java
@@ -0,0 +1,72 @@
+package bowling.view;
+
+import bowling.domain.*;
+
+public class ResultView {
+
+ public static void printRound(Name name, Round round) {
+ System.out.println("| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |");
+ System.out.printf("| %s |", name.getName());
+
+ round.forEach(ResultView::printFrame);
+ System.out.println();
+ }
+
+ private static void printFrame(Frame frame) {
+ String frameString = " ";
+ FrameStatus firstStatus = frame.getFirstStatus();
+ frameString += getFrameCharacter(firstStatus, frame.getFirstHit());
+ FrameStatus secondStatus = frame.getSecondStatus();
+ frameString += getSecondFrameCharacter(secondStatus, frame.getSecondHit());
+ FrameStatus thirdStatus = frame.getThirdStatus();
+ frameString += getThirdFrameCharacter(thirdStatus, frame.getThirdHit());
+ System.out.print(frameString);
+ }
+
+ private static String getFrameCharacter(FrameStatus frameStatus, Hit hit) {
+ if (frameStatus == FrameStatus.BEFORE) {
+ return " ";
+ }
+ if (frameStatus == FrameStatus.STRIKE) {
+ return "X";
+ }
+ if (frameStatus == FrameStatus.GUTTER) {
+ return "-";
+ }
+ return Integer.toString(hit.getScore());
+ }
+
+ private static String getSecondFrameCharacter(FrameStatus frameStatus, Hit hit) {
+ if (frameStatus == FrameStatus.BEFORE
+ || frameStatus == FrameStatus.SKIP) {
+ return " ";
+ }
+ if (frameStatus == FrameStatus.GUTTER) {
+ return "|-";
+ }
+ if (frameStatus == FrameStatus.SPARE) {
+ return "|/";
+ }
+ if (frameStatus == FrameStatus.STRIKE) {
+ return "|X";
+ }
+ return String.format("|%d", hit.getScore());
+ }
+
+ private static String getThirdFrameCharacter(FrameStatus frameStatus, Hit hit) {
+ if (frameStatus == FrameStatus.BEFORE
+ || frameStatus == FrameStatus.SKIP) {
+ return " |";
+ }
+ if (frameStatus == FrameStatus.GUTTER) {
+ return "|-|";
+ }
+ if (frameStatus == FrameStatus.SPARE) {
+ return "|/|";
+ }
+ if (frameStatus == FrameStatus.STRIKE) {
+ return "|X|";
+ }
+ return String.format("|%d|", hit.getScore());
+ }
+}
diff --git a/src/test/java/bowling/domain/HitTest.java b/src/test/java/bowling/domain/HitTest.java
new file mode 100644
index 0000000000..7aaa3465af
--- /dev/null
+++ b/src/test/java/bowling/domain/HitTest.java
@@ -0,0 +1,40 @@
+package bowling.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+public class HitTest {
+
+ @Test
+ @DisplayName("최댓값 테스트")
+ void max() {
+ Hit hit = new Hit(Hit.MAX);
+ assertThat(hit.isMax()).isTrue();
+ assertThat(hit.isMin()).isFalse();
+ }
+
+ @Test
+ @DisplayName("최솟값 테스트")
+ void min() {
+ Hit hit = new Hit(Hit.MIN);
+ assertThat(hit.isMax()).isFalse();
+ assertThat(hit.isMin()).isTrue();
+ }
+
+ @Test
+ @DisplayName("범위 초과 테스트")
+ void range() {
+ assertThatExceptionOfType(IllegalArgumentException.class)
+ .isThrownBy(() -> new Hit(11));
+ }
+
+ @Test
+ @DisplayName("add에 의한 범위 초과 테스트")
+ void range_add() {
+ assertThatExceptionOfType(IllegalArgumentException.class)
+ .isThrownBy(() -> new Hit(3).plus(new Hit(8)));
+ }
+}
diff --git a/src/test/java/bowling/domain/LastFrameTest.java b/src/test/java/bowling/domain/LastFrameTest.java
new file mode 100644
index 0000000000..85aea89884
--- /dev/null
+++ b/src/test/java/bowling/domain/LastFrameTest.java
@@ -0,0 +1,99 @@
+package bowling.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class LastFrameTest {
+
+ @Test
+ @DisplayName("첫번째 투구에 스트라이크를 친 경우 3회째 투구 가능")
+ void strike_first() {
+ Frame frame = new LastFrame();
+ frame.play(new Hit(10));
+ frame.play(new Hit(5));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(10));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.STRIKE);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(5));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.MISS);
+ assertThat(frame.isEnd()).isFalse();
+ }
+
+ @Test
+ @DisplayName("스페어인 경우 세번째 투구 가능")
+ void spare() {
+ Frame frame = new LastFrame();
+ frame.play(new Hit(8));
+ frame.play(new Hit(2));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(8));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.MISS);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(2));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.SPARE);
+ assertThat(frame.isEnd()).isFalse();
+ }
+
+ @Test
+ @DisplayName("3회 스트라이크")
+ void strike() {
+ Frame frame = new LastFrame();
+ frame.play(new Hit(10));
+ frame.play(new Hit(10));
+ frame.play(new Hit(10));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(10));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.STRIKE);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(10));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.STRIKE);
+ assertThat(frame.getThirdHit()).isEqualTo(new Hit(10));
+ assertThat(frame.getThirdStatus()).isEqualTo(FrameStatus.STRIKE);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("거터")
+ void gutter() {
+ Frame frame = new LastFrame();
+ frame.play(new Hit(0));
+ frame.play(new Hit(5));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.GUTTER);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(5));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.MISS);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("두번의 투구 모두 거터")
+ void gutter_2() {
+ Frame frame = new LastFrame();
+ frame.play(new Hit(0));
+ frame.play(new Hit(0));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.GUTTER);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.GUTTER);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("종료되지 않은 상태 테스트")
+ void isEnd() {
+ Frame frame = new LastFrame();
+
+ assertThat(frame.isEnd()).isFalse();
+ }
+
+ @Test
+ @DisplayName("한번 던져서 스트라이크를 치지 않은 뒤 종료되지 않은 상태 테스트")
+ void isEnd_afterFirst() {
+ Frame frame = new LastFrame();
+ frame.play(new Hit(5));
+
+ assertThat(frame.isEnd()).isFalse();
+ }
+}
diff --git a/src/test/java/bowling/domain/NameTest.java b/src/test/java/bowling/domain/NameTest.java
new file mode 100644
index 0000000000..c09142160a
--- /dev/null
+++ b/src/test/java/bowling/domain/NameTest.java
@@ -0,0 +1,27 @@
+package bowling.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+public class NameTest {
+
+ @Test
+ @DisplayName("기본기능 테스트")
+ void name() {
+ Name name = new Name("ASD");
+ assertThat(name.getName()).isEqualTo("ASD");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"AA", "DDDD"})
+ @DisplayName("범위를 벗어나는 이름 테스트")
+ void name_range(String value) {
+ assertThatExceptionOfType(IllegalArgumentException.class)
+ .isThrownBy(() -> new Name(value));
+ }
+}
diff --git a/src/test/java/bowling/domain/NormalFrameTest.java b/src/test/java/bowling/domain/NormalFrameTest.java
new file mode 100644
index 0000000000..7651b50c76
--- /dev/null
+++ b/src/test/java/bowling/domain/NormalFrameTest.java
@@ -0,0 +1,81 @@
+package bowling.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class NormalFrameTest {
+
+ @Test
+ @DisplayName("스트라이크")
+ void strike() {
+ Frame frame = new NormalFrame();
+ frame.play(new Hit(10));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(10));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.STRIKE);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.SKIP);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("스페어")
+ void spare() {
+ Frame frame = new NormalFrame();
+ frame.play(new Hit(8));
+ frame.play(new Hit(2));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(8));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.MISS);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(2));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.SPARE);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("거터")
+ void gutter() {
+ Frame frame = new NormalFrame();
+ frame.play(new Hit(0));
+ frame.play(new Hit(5));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.GUTTER);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(5));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.MISS);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("두번의 투구 모두 거터")
+ void gutter_2() {
+ Frame frame = new NormalFrame();
+ frame.play(new Hit(0));
+ frame.play(new Hit(0));
+
+ assertThat(frame.getFirstHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getFirstStatus()).isEqualTo(FrameStatus.GUTTER);
+ assertThat(frame.getSecondHit()).isEqualTo(new Hit(0));
+ assertThat(frame.getSecondStatus()).isEqualTo(FrameStatus.GUTTER);
+ assertThat(frame.isEnd()).isTrue();
+ }
+
+ @Test
+ @DisplayName("종료되지 않은 상태 테스트")
+ void isEnd() {
+ Frame frame = new NormalFrame();
+
+ assertThat(frame.isEnd()).isFalse();
+ }
+
+ @Test
+ @DisplayName("한번 던져서 스트라이크를 치지 않은 뒤 종료되지 않은 상태 테스트")
+ void isEnd_afterFirst() {
+ Frame frame = new NormalFrame();
+ frame.play(new Hit(5));
+
+ assertThat(frame.isEnd()).isFalse();
+ }
+}
diff --git a/src/test/java/bowling/domain/RoundTest.java b/src/test/java/bowling/domain/RoundTest.java
new file mode 100644
index 0000000000..1646043c76
--- /dev/null
+++ b/src/test/java/bowling/domain/RoundTest.java
@@ -0,0 +1,49 @@
+package bowling.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RoundTest {
+
+ @Test
+ @DisplayName("초기 상태 테스트")
+ void round_init() {
+ Round round = new Round();
+
+ assertThat(round.isEnd()).isFalse();
+ assertThat(round.getCurrentFrameNumber()).isEqualTo(1);
+ }
+
+ @Test
+ @DisplayName("스트라이크 투구 테스트")
+ void round_hit() {
+ Round round = new Round();
+ round.hit(new Hit(10));
+ round.hit(new Hit(5));
+
+ assertThat(round.isEnd()).isFalse();
+ assertThat(round.getCurrentFrameNumber()).isEqualTo(2);
+ }
+
+ @Test
+ @DisplayName("라운드 종료 테스트")
+ void round_end() {
+ Round round = new Round();
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(10));
+ round.hit(new Hit(5));
+ round.hit(new Hit(4));
+
+ assertThat(round.isEnd()).isTrue();
+ assertThat(round.getCurrentFrameNumber()).isEqualTo(10);
+ }
+}