From c5928a78811a641b34cdbb2871fa9f33645603b2 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:12:28 +0900 Subject: [PATCH 01/13] =?UTF-8?q?DOCS:=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=EA=B3=BC=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=EB=B0=8D=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 76 ++++++++++++++++++++++++++++++++++++++++++ src/main/java/.gitkeep | 0 2 files changed, 76 insertions(+) create mode 100644 README.md delete mode 100644 src/main/java/.gitkeep diff --git a/README.md b/README.md new file mode 100644 index 00000000..a9823886 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +## 움직이는 자동차 [O] +### 기능 요구사항 +- 자동차는 이름을 가지고 있다. +- 자동차는 움직일 수 있다. +- 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. +### 새로운 프로그래밍 요구사항 +- 자동차가 움직이는 기능이 의도대로 동작하는지 테스트한다. +- 자바 코드 컨벤션을 지키면서 프로그래밍한다. +- 기본적으로 Java Style Guide을 원칙으로 한다. +- indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. + - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. + - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. +- 3항 연산자를 쓰지 않는다. +- else 예약어를 쓰지 않는다. + - else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. + - 힌트: if문에서 값을 반환하는 방식으로 구현하면 else 예약어를 사용하지 않아도 된다. +- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다. + - 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다. +### 기존 프로그래밍 요구사항 +- 메인 메서드는 만들지 않는다. + +## 우승 자동차 구하기 [O] +### 기능 요구사항 +- n대의 자동차가 참여할 수 있다. +- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. + - 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. +- 자동차 경주 게임을 완료한 후 누가 우승했는지를 구할 수 있다. 우승자는 한 명 이상일 수 있다. +### 새로운 프로그래밍 요구사항 +- 우승자를 구하는 기능이 의도대로 동작하는지 테스트한다. + +## 게임 실행 [O] +### 기능 요구사항 +- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. +- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. +- 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다. +- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. +- 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. +- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. +
**실행 결과** +- 위 요구사항에 따라 3대의 자동차가 5번 움직였을 경우 프로그램을 실행한 결과는 다음과 같다. +``` +경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분). +neo,brie,brown +시도할 회수는 몇회인가요? +5 + +실행 결과 +neo : - +brie : - +brown : - + +neo : -- +brie : - +brown : -- + +neo : --- +brie : -- +brown : --- + +neo : ---- +brie : --- +brown : ---- + +neo : ----- +brie : ---- +brown : ----- + +neo : ----- +brie : ---- +brown : ----- + +neo, brown가 최종 우승했습니다. +``` + +### 새로운 프로그래밍 요구사항 +- 메인 메서드를 추가하여 실행 가능한 애플리케이션으로 만든다. \ No newline at end of file diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 From 298065d41658c99cf5d2fe453e581c340a359fe8 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:12:48 +0900 Subject: [PATCH 02/13] =?UTF-8?q?Remove:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20.gitkeep=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/test/java/.gitkeep diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 From 49ecbf807af2799e03049937bcc1130e57ac8b54 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:13:39 +0900 Subject: [PATCH 03/13] =?UTF-8?q?Feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/RacingCar.java | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/main/java/RacingCar.java diff --git a/src/main/java/RacingCar.java b/src/main/java/RacingCar.java new file mode 100644 index 00000000..fbe76af4 --- /dev/null +++ b/src/main/java/RacingCar.java @@ -0,0 +1,49 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class RacingCar { + private final String name; + private int score = 0; + private final List results = new ArrayList<>(); + + public RacingCar(String name) { + this.name = name; + } + + public int move() { + Random rand = new Random(); + + boolean result = rand.nextInt(10) >= 4; + + if (result) + ++score; + + results.add(result); + + return score; + } + + public String getName() { + return name; + } + + public int getScore() { + return score; + } + + public String getResultString(int phase) { + StringBuilder resultString = new StringBuilder(); + for (int i = 0; i < phase && i < results.size(); i++) { + resultString.append(resultToString(results.get(i))); + } + return resultString.toString(); + } + + private String resultToString(Boolean result) { + if (result) + return "-"; + + return ""; + } +} From 1ca6611d3f160fc0ae53c3c3fb748e22f195f7e0 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:14:10 +0900 Subject: [PATCH 04/13] =?UTF-8?q?Feat:=20=EC=9A=B0=EC=8A=B9=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=20=EA=B5=AC=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/RacingCarGame.java | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/main/java/RacingCarGame.java diff --git a/src/main/java/RacingCarGame.java b/src/main/java/RacingCarGame.java new file mode 100644 index 00000000..e7dd7656 --- /dev/null +++ b/src/main/java/RacingCarGame.java @@ -0,0 +1,87 @@ +import java.util.ArrayList; +import java.util.InputMismatchException; +import java.util.List; +import java.util.Scanner; + +public class RacingCarGame { + + int highScore; + int phase = 0; + List racingCars = new ArrayList<>(); + boolean isGameInit = false; + + public void setGame() { + Scanner scanner = new Scanner(System.in); + + System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); + String input = scanner.nextLine(); + + for (String name : input.split(",")) + racingCars.add(new RacingCar(name)); + + if (racingCars.size() < 2) + throw new InputMismatchException("최소한 두 명 이상의 플레이어가 필요합니다."); + + System.out.println("시도할 회수는 몇회인가요?"); + try { + phase = scanner.nextInt(); + if (phase < 0) { + throw new NumberFormatException("음수는 유효한 숫자가 아닙니다."); + } + } catch (InputMismatchException e) { + throw new InputMismatchException("유효한 숫자가 아닙니다."); + } + + + isGameInit = true; + } + + public void startGame() { + if (!isGameInit) + throw new IllegalStateException("게임이 초기화되지 않았습니다."); + + for(int i = 0; i < phase; ++i){ + moveAllRacingCars(); + } + + printResult(); + } + + public void resetGame() { + racingCars.clear(); + highScore = 0; + } + + private void moveAllRacingCars() { + for(RacingCar racingCar : racingCars) + racingCar.move(); + } + + private void printResult() { + System.out.println("\n실행 결과"); + + for (int i = 1; i <= phase; ++i){ + printAllRacingCarResults(i); + System.out.println(); + } + + System.out.println(String.join(", ", getWinnerNames()) + "가 최종 우승했습니다."); + } + + private void printAllRacingCarResults(int phase) { + for (RacingCar racingCar : racingCars) { + System.out.println(racingCar.getName() + " : " + racingCar.getResultString(phase)); + } + } + + private List getWinnerNames() { + return racingCars.stream().filter(this::checkWinner).map(RacingCar::getName).toList(); + } + + private boolean checkWinner(RacingCar racingCar) { + if (racingCar.getScore() > highScore) + highScore = racingCar.getScore(); + + return racingCar.getScore() == highScore; + } +} From f461973c2356c76ba6af4aeb1b35a2ba498d99cd Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:15:26 +0900 Subject: [PATCH 05/13] =?UTF-8?q?Feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8?= =?UTF-8?q?=EC=99=80=20=EA=B2=8C=EC=9E=84=20=EA=B4=80=EB=A0=A8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/RacingCarTest.java | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/test/java/RacingCarTest.java diff --git a/src/test/java/RacingCarTest.java b/src/test/java/RacingCarTest.java new file mode 100644 index 00000000..955cd089 --- /dev/null +++ b/src/test/java/RacingCarTest.java @@ -0,0 +1,67 @@ +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.ByteArrayInputStream; +import java.util.InputMismatchException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class RacingCarTest { + + @Test + @DisplayName("자동차 이동 테스트") + void racingCarMove() { + RacingCar racingCar = new RacingCar("Test"); + int expected = racingCar.getScore(); + int actual = racingCar.move(); + + assertThat(actual).isIn(expected, expected + 1); + } + + @Test + @DisplayName("자동차 결과 텍스트 테스트") + void racingCarResultString() { + RacingCar racingCar = new RacingCar("Test"); + + for (int i = 0; i < 5; ++i) + racingCar.move(); + + + String actual = racingCar.getResultString(5); + String expected = new String(new char[racingCar.getScore()]).replace("\0", "-"); + + assertThat(actual).isEqualTo(expected); + } + + @Nested + @DisplayName("자동차 게임 설정 테스트") + class setGame { + @Test + @DisplayName("자동차 이름 입력이 하나일 경우 테스트") + void setGameWithLessThanTwoNameInput() { + RacingCarGame racingCarGame = new RacingCarGame(); + System.setIn(new ByteArrayInputStream("test1\n1".getBytes())); + + assertThatThrownBy(racingCarGame::setGame).isInstanceOf(InputMismatchException.class).hasMessage("최소한 두 명 이상의 플레이어가 필요합니다."); + } + + @Test + @DisplayName("시도할 횟수 입력이 음수일 경우 테스트") + void setGameWithNegativePhaseInput() { + RacingCarGame racingCarGame = new RacingCarGame(); + System.setIn(new ByteArrayInputStream("test1,test2\n-1\n".getBytes())); + + assertThatThrownBy(racingCarGame::setGame).isInstanceOf(NumberFormatException.class).hasMessage("음수는 유효한 숫자가 아닙니다."); + } + + @Test + @DisplayName("시도할 횟수 입력이 숫자가 아닌 경우 테스트") + void setGameWithInvalidPhaseInput() { + RacingCarGame racingCarGame = new RacingCarGame(); + System.setIn(new ByteArrayInputStream("test1,test2\nabc\n".getBytes())); + + assertThatThrownBy(racingCarGame::setGame).isInstanceOf(InputMismatchException.class).hasMessage("유효한 숫자가 아닙니다."); + } + } +} From e6a5ecef0db14533bfb0489b63984e95977f97b8 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:15:49 +0900 Subject: [PATCH 06/13] =?UTF-8?q?Feat:=20=EA=B2=8C=EC=9E=84=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=20=EA=B0=80=EB=8A=A5=ED=95=9C=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Main.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/Main.java diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 00000000..d5e19f46 --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,8 @@ +public class Main { + public static void main(String[] args) { + RacingCarGame game = new RacingCarGame(); + game.setGame(); + game.startGame(); + game.resetGame(); + } +} From 5e1aff276ab8571322754e1ec11f26b6ba68da60 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Sat, 5 Oct 2024 04:44:19 +0900 Subject: [PATCH 07/13] =?UTF-8?q?Fix:=20=EC=B1=85=EC=9E=84=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20randPower=EC=99=80=20?= =?UTF-8?q?checkPower=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=ED=9B=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=84=B8=EB=B6=84?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/RacingCar.java | 22 +++++++++++++--- src/test/java/RacingCarTest.java | 44 +++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/main/java/RacingCar.java b/src/main/java/RacingCar.java index fbe76af4..e264cefd 100644 --- a/src/main/java/RacingCar.java +++ b/src/main/java/RacingCar.java @@ -11,19 +11,33 @@ public RacingCar(String name) { this.name = name; } - public int move() { + private int randPower() { Random rand = new Random(); + return rand.nextInt(10); + } - boolean result = rand.nextInt(10) >= 4; + public int move() { + return move(randPower()); + } - if (result) + public int move(int power) { + boolean isMovable = checkPower(power); + + if (isMovable) ++score; - results.add(result); + results.add(isMovable); return score; } + private boolean checkPower(int power) { + if (power < 0 || power > 9) + throw new IllegalArgumentException("0~9 사이의 Power 값을 필요로 합니다."); + + return power >= 4; + } + public String getName() { return name; } diff --git a/src/test/java/RacingCarTest.java b/src/test/java/RacingCarTest.java index 955cd089..3327e0ac 100644 --- a/src/test/java/RacingCarTest.java +++ b/src/test/java/RacingCarTest.java @@ -9,15 +9,45 @@ public class RacingCarTest { - @Test + @Nested @DisplayName("자동차 이동 테스트") - void racingCarMove() { - RacingCar racingCar = new RacingCar("Test"); - int expected = racingCar.getScore(); - int actual = racingCar.move(); + class RacingCarMove { + @Test + @DisplayName("자동차 랜덤 이동 테스트") + void randomMove() { + RacingCar racingCar = new RacingCar("Test"); + int expected = racingCar.getScore(); + int actual = racingCar.move(); + + assertThat(actual).isIn(expected, expected + 1); + } + + @Test + @DisplayName("자동차 이동 조건 테스트") + void moveCondition() { + RacingCar racingCar = new RacingCar("Test"); + int expected = 0; + int actual = racingCar.move(3); - assertThat(actual).isIn(expected, expected + 1); + assertThat(actual).isEqualTo(expected); + + expected = 1; + actual = racingCar.move(5); + + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("자동차 이동 조건 예외처리 테스트") + void moveConditionException() { + RacingCar racingCar = new RacingCar("Test"); + + assertThatThrownBy(() -> racingCar.move(-1)).isInstanceOf(IllegalArgumentException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); + + assertThatThrownBy(() -> racingCar.move(10)).isInstanceOf(IllegalArgumentException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); + } } + @Test @DisplayName("자동차 결과 텍스트 테스트") @@ -36,7 +66,7 @@ void racingCarResultString() { @Nested @DisplayName("자동차 게임 설정 테스트") - class setGame { + class SetRacingCarGameTest { @Test @DisplayName("자동차 이름 입력이 하나일 경우 테스트") void setGameWithLessThanTwoNameInput() { From 74656e577d24164459596e8d579b8fbc22f2cce2 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Fri, 11 Oct 2024 07:58:08 +0900 Subject: [PATCH 08/13] Remove: Remove class unused in mvc model --- src/main/java/Main.java | 8 ----- src/main/java/RacingCar.java | 63 ------------------------------------ 2 files changed, 71 deletions(-) delete mode 100644 src/main/java/Main.java delete mode 100644 src/main/java/RacingCar.java diff --git a/src/main/java/Main.java b/src/main/java/Main.java deleted file mode 100644 index d5e19f46..00000000 --- a/src/main/java/Main.java +++ /dev/null @@ -1,8 +0,0 @@ -public class Main { - public static void main(String[] args) { - RacingCarGame game = new RacingCarGame(); - game.setGame(); - game.startGame(); - game.resetGame(); - } -} diff --git a/src/main/java/RacingCar.java b/src/main/java/RacingCar.java deleted file mode 100644 index e264cefd..00000000 --- a/src/main/java/RacingCar.java +++ /dev/null @@ -1,63 +0,0 @@ -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -public class RacingCar { - private final String name; - private int score = 0; - private final List results = new ArrayList<>(); - - public RacingCar(String name) { - this.name = name; - } - - private int randPower() { - Random rand = new Random(); - return rand.nextInt(10); - } - - public int move() { - return move(randPower()); - } - - public int move(int power) { - boolean isMovable = checkPower(power); - - if (isMovable) - ++score; - - results.add(isMovable); - - return score; - } - - private boolean checkPower(int power) { - if (power < 0 || power > 9) - throw new IllegalArgumentException("0~9 사이의 Power 값을 필요로 합니다."); - - return power >= 4; - } - - public String getName() { - return name; - } - - public int getScore() { - return score; - } - - public String getResultString(int phase) { - StringBuilder resultString = new StringBuilder(); - for (int i = 0; i < phase && i < results.size(); i++) { - resultString.append(resultToString(results.get(i))); - } - return resultString.toString(); - } - - private String resultToString(Boolean result) { - if (result) - return "-"; - - return ""; - } -} From 664ce8d41ab81b787b5c07d9537e4626bd961a63 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Fri, 11 Oct 2024 07:59:26 +0900 Subject: [PATCH 09/13] Refactor: Refactor design pattern to mvc model --- src/main/java/RacingCarGame.java | 96 +++---------------- .../java/controller/RacingCarController.java | 39 ++++++++ .../java/converter/RacingCarConverter.java | 27 ++++++ src/main/java/dao/RacingCarDao.java | 20 ++++ src/main/java/domain/RacingCar.java | 15 +++ src/main/java/dto/RacingCarCreateDto.java | 14 +++ src/main/java/dto/RacingCarResultDto.java | 16 ++++ src/main/java/service/RacingCarService.java | 13 +++ .../java/service/RacingCarServiceImpl.java | 36 +++++++ src/main/java/view/RacingCarView.java | 45 +++++++++ 10 files changed, 238 insertions(+), 83 deletions(-) create mode 100644 src/main/java/controller/RacingCarController.java create mode 100644 src/main/java/converter/RacingCarConverter.java create mode 100644 src/main/java/dao/RacingCarDao.java create mode 100644 src/main/java/domain/RacingCar.java create mode 100644 src/main/java/dto/RacingCarCreateDto.java create mode 100644 src/main/java/dto/RacingCarResultDto.java create mode 100644 src/main/java/service/RacingCarService.java create mode 100644 src/main/java/service/RacingCarServiceImpl.java create mode 100644 src/main/java/view/RacingCarView.java diff --git a/src/main/java/RacingCarGame.java b/src/main/java/RacingCarGame.java index e7dd7656..eb07fee6 100644 --- a/src/main/java/RacingCarGame.java +++ b/src/main/java/RacingCarGame.java @@ -1,87 +1,17 @@ -import java.util.ArrayList; -import java.util.InputMismatchException; -import java.util.List; -import java.util.Scanner; +import controller.RacingCarController; +import dao.RacingCarDao; +import service.RacingCarService; +import service.RacingCarServiceImpl; +import view.RacingCarView; public class RacingCarGame { - - int highScore; - int phase = 0; - List racingCars = new ArrayList<>(); - boolean isGameInit = false; - - public void setGame() { - Scanner scanner = new Scanner(System.in); - - System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); - String input = scanner.nextLine(); - - for (String name : input.split(",")) - racingCars.add(new RacingCar(name)); - - if (racingCars.size() < 2) - throw new InputMismatchException("최소한 두 명 이상의 플레이어가 필요합니다."); - - System.out.println("시도할 회수는 몇회인가요?"); - try { - phase = scanner.nextInt(); - if (phase < 0) { - throw new NumberFormatException("음수는 유효한 숫자가 아닙니다."); - } - } catch (InputMismatchException e) { - throw new InputMismatchException("유효한 숫자가 아닙니다."); - } - - - isGameInit = true; - } - - public void startGame() { - if (!isGameInit) - throw new IllegalStateException("게임이 초기화되지 않았습니다."); - - for(int i = 0; i < phase; ++i){ - moveAllRacingCars(); - } - - printResult(); - } - - public void resetGame() { - racingCars.clear(); - highScore = 0; - } - - private void moveAllRacingCars() { - for(RacingCar racingCar : racingCars) - racingCar.move(); - } - - private void printResult() { - System.out.println("\n실행 결과"); - - for (int i = 1; i <= phase; ++i){ - printAllRacingCarResults(i); - System.out.println(); - } - - System.out.println(String.join(", ", getWinnerNames()) + "가 최종 우승했습니다."); - } - - private void printAllRacingCarResults(int phase) { - for (RacingCar racingCar : racingCars) { - System.out.println(racingCar.getName() + " : " + racingCar.getResultString(phase)); - } - } - - private List getWinnerNames() { - return racingCars.stream().filter(this::checkWinner).map(RacingCar::getName).toList(); - } - - private boolean checkWinner(RacingCar racingCar) { - if (racingCar.getScore() > highScore) - highScore = racingCar.getScore(); - - return racingCar.getScore() == highScore; + public static void main(String[] args) { + RacingCarView racingCarView = new RacingCarView(); + RacingCarDao racingCarDao = new RacingCarDao(); + RacingCarService racingCarService = new RacingCarServiceImpl(racingCarDao); + RacingCarController game = new RacingCarController(racingCarView, racingCarService); + + game.set(); + game.run(); } } diff --git a/src/main/java/controller/RacingCarController.java b/src/main/java/controller/RacingCarController.java new file mode 100644 index 00000000..4b03f50b --- /dev/null +++ b/src/main/java/controller/RacingCarController.java @@ -0,0 +1,39 @@ +package controller; + +import converter.RacingCarConverter; +import lombok.RequiredArgsConstructor; +import service.RacingCarService; +import view.RacingCarView; + +@RequiredArgsConstructor +public class RacingCarController { + + final RacingCarView racingCarView; + final RacingCarService racingCarService; + + int round; + boolean isGameInit = false; + + public void set() { + racingCarService.createRacingCar(racingCarView.inputRacingCarName().stream().map( + RacingCarConverter::toRacingCarCreateDto).toList()); + round = racingCarView.inputRound(); + + isGameInit = true; + } + + public void run() { + if (!isGameInit) + throw new IllegalStateException("게임이 초기화되지 않았습니다."); + + racingCarView.printResultTitle(); + for(int currentRound = 0; currentRound < round; ++currentRound){ + racingCarService.move(); + racingCarView.printResult(racingCarService.getResults()); + } + + racingCarView.printWinner(racingCarService.getResults()); + + isGameInit = false; + } +} diff --git a/src/main/java/converter/RacingCarConverter.java b/src/main/java/converter/RacingCarConverter.java new file mode 100644 index 00000000..8486fbb5 --- /dev/null +++ b/src/main/java/converter/RacingCarConverter.java @@ -0,0 +1,27 @@ +package converter; + +import domain.RacingCar; +import dto.RacingCarCreateDto; +import dto.RacingCarResultDto; +import java.util.stream.Collectors; + +public class RacingCarConverter { + public static RacingCarCreateDto toRacingCarCreateDto(String name) { + return RacingCarCreateDto.builder().name(name).build(); + } + + public static RacingCarResultDto toRacingCarResultDto(RacingCar racingCar) { + return RacingCarResultDto.builder(). + name(racingCar.getName()) + .resultString(racingCar.getResults().stream().map(RacingCarConverter::resultToString).collect( + Collectors.joining())) + .distance((int) racingCar.getResults().stream().filter(v -> v).count()).build(); + } + + public static String resultToString(Boolean result) { + if (result) + return "-"; + + return ""; + } +} diff --git a/src/main/java/dao/RacingCarDao.java b/src/main/java/dao/RacingCarDao.java new file mode 100644 index 00000000..a6075410 --- /dev/null +++ b/src/main/java/dao/RacingCarDao.java @@ -0,0 +1,20 @@ +package dao; + +import domain.RacingCar; +import dto.RacingCarCreateDto; +import java.util.ArrayList; +import java.util.List; + +public class RacingCarDao { + private final List racingCars = new ArrayList<>(); + + public RacingCar insert(RacingCarCreateDto racingCarCreateDto) { + RacingCar racingCar = new RacingCar(racingCarCreateDto.getName()); + racingCars.add(racingCar); + return racingCar; + } + + public List select() { + return racingCars; + } +} diff --git a/src/main/java/domain/RacingCar.java b/src/main/java/domain/RacingCar.java new file mode 100644 index 00000000..813e634f --- /dev/null +++ b/src/main/java/domain/RacingCar.java @@ -0,0 +1,15 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@RequiredArgsConstructor +public class RacingCar { + private final String name; + private final List results = new ArrayList<>(); +} diff --git a/src/main/java/dto/RacingCarCreateDto.java b/src/main/java/dto/RacingCarCreateDto.java new file mode 100644 index 00000000..536c6fcb --- /dev/null +++ b/src/main/java/dto/RacingCarCreateDto.java @@ -0,0 +1,14 @@ +package dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class RacingCarCreateDto { + private String name; +} diff --git a/src/main/java/dto/RacingCarResultDto.java b/src/main/java/dto/RacingCarResultDto.java new file mode 100644 index 00000000..29d0d9eb --- /dev/null +++ b/src/main/java/dto/RacingCarResultDto.java @@ -0,0 +1,16 @@ +package dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class RacingCarResultDto { + private String name; + private String resultString; + private int distance; +} diff --git a/src/main/java/service/RacingCarService.java b/src/main/java/service/RacingCarService.java new file mode 100644 index 00000000..31329d38 --- /dev/null +++ b/src/main/java/service/RacingCarService.java @@ -0,0 +1,13 @@ +package service; + +import dto.RacingCarCreateDto; +import dto.RacingCarResultDto; +import java.util.List; + +public interface RacingCarService { + void createRacingCar(List racingCarCreateDtoList); + + void move(); + + List getResults(); +} diff --git a/src/main/java/service/RacingCarServiceImpl.java b/src/main/java/service/RacingCarServiceImpl.java new file mode 100644 index 00000000..a9ddd97f --- /dev/null +++ b/src/main/java/service/RacingCarServiceImpl.java @@ -0,0 +1,36 @@ +package service; + +import converter.RacingCarConverter; +import dao.RacingCarDao; +import domain.RacingCar; +import dto.RacingCarCreateDto; +import dto.RacingCarResultDto; +import java.util.List; +import java.util.Random; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class RacingCarServiceImpl implements RacingCarService { + final RacingCarDao racingCarDao; + + @Override + public void createRacingCar(final List racingCarCreateDtoList) { + List racingCars = racingCarCreateDtoList.stream().map(racingCarDao::insert).toList(); + } + + @Override + public void move() { + for (RacingCar racingCar : racingCarDao.select()){ + Random rand = new Random(); + + boolean result = rand.nextInt(10) >= 4; + + racingCar.getResults().add(result); + } + } + + @Override + public List getResults() { + return racingCarDao.select().stream().map(RacingCarConverter::toRacingCarResultDto).toList(); + } +} diff --git a/src/main/java/view/RacingCarView.java b/src/main/java/view/RacingCarView.java new file mode 100644 index 00000000..eebf7f01 --- /dev/null +++ b/src/main/java/view/RacingCarView.java @@ -0,0 +1,45 @@ +package view; + +import dto.RacingCarResultDto; +import java.util.List; +import java.util.Scanner; + +public class RacingCarView { + + public List inputRacingCarName() { + Scanner scanner = new Scanner(System.in); + + System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); + String input = scanner.nextLine(); + + return List.of(input.split(",")); + } + + public int inputRound() { + Scanner scanner = new Scanner(System.in); + + System.out.println("시도할 회수는 몇회인가요?"); + int round = scanner.nextInt(); + + return round; + } + + public void printResultTitle() { + System.out.println("\n실행 결과"); + } + + public void printResult(List racingCarResultDtoList) { + for (RacingCarResultDto racingCarResultDto : racingCarResultDtoList) { + System.out.printf("%s : %s%n", racingCarResultDto.getName(), racingCarResultDto.getResultString()); + } + System.out.println(); + } + + public void printWinner(List racingCarResultDtoList) { + int maxDistance = racingCarResultDtoList.stream().mapToInt(RacingCarResultDto::getDistance).max().orElseThrow(); + + List winners = racingCarResultDtoList.stream().filter(v -> v.getDistance() == maxDistance).map(RacingCarResultDto::getName).toList(); + + System.out.println(String.join(", ", winners) + "가 최종 우승했습니다."); + } +} From 83fbd7190d0aafa7c325078145aeae90f5e827ea Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:00:54 +0900 Subject: [PATCH 10/13] Refactor: Add implementation of lombok --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 239f9e78..85891c16 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,8 @@ dependencies { testImplementation platform('org.assertj:assertj-bom:3.25.1') testImplementation('org.junit.jupiter:junit-jupiter') testImplementation('org.assertj:assertj-core') + compileOnly("org.projectlombok:lombok:1.18.34") + annotationProcessor('org.projectlombok:lombok:1.18.34') } test { From 13a911b171ab64c8cfb453ad3100a07bfd3325c4 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:26:21 +0900 Subject: [PATCH 11/13] Refactor: Add implementation of mockito --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 85891c16..8d5f4636 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,7 @@ dependencies { testImplementation platform('org.assertj:assertj-bom:3.25.1') testImplementation('org.junit.jupiter:junit-jupiter') testImplementation('org.assertj:assertj-core') + testImplementation("org.mockito:mockito-core:5.14.1") compileOnly("org.projectlombok:lombok:1.18.34") annotationProcessor('org.projectlombok:lombok:1.18.34') } From 1a3d4b56b342305467a8f9ea882d851e305a92a0 Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:40:41 +0900 Subject: [PATCH 12/13] Feat: Add NumberGenerateUtil as Bean for test --- src/main/java/RacingCarGame.java | 4 +++- src/main/java/service/RacingCarServiceImpl.java | 12 +++++++----- src/main/java/util/NumberGenerateUtil.java | 11 +++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 src/main/java/util/NumberGenerateUtil.java diff --git a/src/main/java/RacingCarGame.java b/src/main/java/RacingCarGame.java index eb07fee6..453a0b2d 100644 --- a/src/main/java/RacingCarGame.java +++ b/src/main/java/RacingCarGame.java @@ -2,13 +2,15 @@ import dao.RacingCarDao; import service.RacingCarService; import service.RacingCarServiceImpl; +import util.NumberGenerateUtil; import view.RacingCarView; public class RacingCarGame { public static void main(String[] args) { RacingCarView racingCarView = new RacingCarView(); RacingCarDao racingCarDao = new RacingCarDao(); - RacingCarService racingCarService = new RacingCarServiceImpl(racingCarDao); + NumberGenerateUtil numberGenerateUtil = new NumberGenerateUtil(); + RacingCarService racingCarService = new RacingCarServiceImpl(racingCarDao, numberGenerateUtil); RacingCarController game = new RacingCarController(racingCarView, racingCarService); game.set(); diff --git a/src/main/java/service/RacingCarServiceImpl.java b/src/main/java/service/RacingCarServiceImpl.java index a9ddd97f..7cfb31e0 100644 --- a/src/main/java/service/RacingCarServiceImpl.java +++ b/src/main/java/service/RacingCarServiceImpl.java @@ -6,12 +6,13 @@ import dto.RacingCarCreateDto; import dto.RacingCarResultDto; import java.util.List; -import java.util.Random; import lombok.RequiredArgsConstructor; +import util.NumberGenerateUtil; @RequiredArgsConstructor public class RacingCarServiceImpl implements RacingCarService { final RacingCarDao racingCarDao; + final NumberGenerateUtil numberGenerateUtil; @Override public void createRacingCar(final List racingCarCreateDtoList) { @@ -21,11 +22,12 @@ public void createRacingCar(final List racingCarCreateDtoLis @Override public void move() { for (RacingCar racingCar : racingCarDao.select()){ - Random rand = new Random(); + int power = numberGenerateUtil.generateRandomNumber(); - boolean result = rand.nextInt(10) >= 4; - - racingCar.getResults().add(result); + if (0 <= power && power <= 9) + racingCar.getResults().add(power >= 4); + else + throw new NumberFormatException("0~9 사이의 Power 값을 필요로 합니다."); } } diff --git a/src/main/java/util/NumberGenerateUtil.java b/src/main/java/util/NumberGenerateUtil.java new file mode 100644 index 00000000..2acba90b --- /dev/null +++ b/src/main/java/util/NumberGenerateUtil.java @@ -0,0 +1,11 @@ +package util; + +import java.security.SecureRandom; + +public class NumberGenerateUtil { + + public int generateRandomNumber() { + SecureRandom secureRandom = new SecureRandom(); + return secureRandom.nextInt(10); + } +} From 68f54a03ccdb3ef8d7e21b351c0b323015e94e1c Mon Sep 17 00:00:00 2001 From: IDLE <83659656+idle2534@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:42:37 +0900 Subject: [PATCH 13/13] Feat: Fix and Add test following mvc pattern --- src/main/java/view/RacingCarView.java | 41 +++++++- src/test/java/RacingCarConverterTest.java | 38 ++++++++ src/test/java/RacingCarTest.java | 114 +++++++--------------- src/test/java/RacingCarViewTest.java | 64 ++++++++++++ 4 files changed, 176 insertions(+), 81 deletions(-) create mode 100644 src/test/java/RacingCarConverterTest.java create mode 100644 src/test/java/RacingCarViewTest.java diff --git a/src/main/java/view/RacingCarView.java b/src/main/java/view/RacingCarView.java index eebf7f01..24875ea7 100644 --- a/src/main/java/view/RacingCarView.java +++ b/src/main/java/view/RacingCarView.java @@ -1,27 +1,60 @@ package view; import dto.RacingCarResultDto; +import java.lang.module.ResolutionException; +import java.util.InputMismatchException; import java.util.List; import java.util.Scanner; +import java.util.regex.Pattern; + public class RacingCarView { + public static class RacingCarInputException extends RuntimeException { + + public RacingCarInputException() { + super("유효하지 않은 입력입니다."); + } + + public RacingCarInputException(final String s) { + super(s); + } + } public List inputRacingCarName() { Scanner scanner = new Scanner(System.in); System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); - String input = scanner.nextLine(); + String input = scanner.nextLine().replaceAll(" ", ""); + + if (Pattern.compile("[!@#$%^&*().?\"{}|<>]").matcher(input).find()) + throw new RacingCarInputException("이름에 특수기호를 입력할 수 없습니다."); - return List.of(input.split(",")); + List names = List.of(input.split(",")); + + if (names.size() <= 1) + throw new RacingCarInputException("최소한 두 명 이상의 플레이어가 필요합니다."); + + + return names; } public int inputRound() { Scanner scanner = new Scanner(System.in); System.out.println("시도할 회수는 몇회인가요?"); - int round = scanner.nextInt(); - return round; + try { + int round = scanner.nextInt(); + + if (round <= 0) + throw new NumberFormatException("횟수는 1회 이상이여야 합니다."); + + return round; + } catch (InputMismatchException e) { + throw new RacingCarInputException(); + } catch (NumberFormatException e) { + throw new RacingCarInputException(e.getMessage()); + } } public void printResultTitle() { diff --git a/src/test/java/RacingCarConverterTest.java b/src/test/java/RacingCarConverterTest.java new file mode 100644 index 00000000..16537fd4 --- /dev/null +++ b/src/test/java/RacingCarConverterTest.java @@ -0,0 +1,38 @@ +import static org.assertj.core.api.Assertions.assertThat; + +import converter.RacingCarConverter; +import domain.RacingCar; +import dto.RacingCarCreateDto; +import dto.RacingCarResultDto; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class RacingCarConverterTest { + + @Test + public void testToRacingCarCreateDto() { + RacingCarCreateDto expected = new RacingCarCreateDto("tester"); + RacingCarCreateDto actual = RacingCarConverter.toRacingCarCreateDto("tester"); + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + + @Test + public void testToRacingCarResultDto() { + RacingCarResultDto expected = new RacingCarResultDto("tester", "---", 3); + RacingCar racingCar = new RacingCar("tester"); + racingCar.getResults().addAll(List.of(false, false, true, true, true)); + RacingCarResultDto actual = RacingCarConverter.toRacingCarResultDto(racingCar); + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testResultToString(boolean value) { + String expected = value ? "-" : ""; + String actual = RacingCarConverter.resultToString(value); + + assertThat(actual).isEqualTo(expected); + } +} diff --git a/src/test/java/RacingCarTest.java b/src/test/java/RacingCarTest.java index 3327e0ac..7b373836 100644 --- a/src/test/java/RacingCarTest.java +++ b/src/test/java/RacingCarTest.java @@ -1,97 +1,57 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.io.ByteArrayInputStream; -import java.util.InputMismatchException; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import converter.RacingCarConverter; +import dao.RacingCarDao; +import dto.RacingCarCreateDto; +import java.util.List; +import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import service.RacingCarService; +import service.RacingCarServiceImpl; +import util.NumberGenerateUtil; public class RacingCarTest { @Nested @DisplayName("자동차 이동 테스트") - class RacingCarMove { - @Test - @DisplayName("자동차 랜덤 이동 테스트") - void randomMove() { - RacingCar racingCar = new RacingCar("Test"); - int expected = racingCar.getScore(); - int actual = racingCar.move(); - - assertThat(actual).isIn(expected, expected + 1); - } - - @Test + class RacingCarMoveTest { + @ParameterizedTest + @ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) @DisplayName("자동차 이동 조건 테스트") - void moveCondition() { - RacingCar racingCar = new RacingCar("Test"); - int expected = 0; - int actual = racingCar.move(3); + void testCondition(int value) { + NumberGenerateUtil numberGenerateUtil = mock(NumberGenerateUtil.class); + when(numberGenerateUtil.generateRandomNumber()).thenReturn(value); + RacingCarDao racingCarDao = new RacingCarDao(); + RacingCarService racingCarService = new RacingCarServiceImpl(racingCarDao, numberGenerateUtil); + List racingCarCreateDtoList = Stream.of("tester1", "tester2").map(v -> RacingCarConverter.toRacingCarCreateDto("")).toList(); + racingCarService.createRacingCar(racingCarCreateDtoList); - assertThat(actual).isEqualTo(expected); + racingCarService.move(); - expected = 1; - actual = racingCar.move(5); + int expected = value >= 4 ? 1 : 0; + int actual = racingCarService.getResults().get(0).getDistance(); assertThat(actual).isEqualTo(expected); } - @Test + @ParameterizedTest + @ValueSource(ints = {-1, 10}) @DisplayName("자동차 이동 조건 예외처리 테스트") - void moveConditionException() { - RacingCar racingCar = new RacingCar("Test"); - - assertThatThrownBy(() -> racingCar.move(-1)).isInstanceOf(IllegalArgumentException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); - - assertThatThrownBy(() -> racingCar.move(10)).isInstanceOf(IllegalArgumentException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); - } - } - - - @Test - @DisplayName("자동차 결과 텍스트 테스트") - void racingCarResultString() { - RacingCar racingCar = new RacingCar("Test"); - - for (int i = 0; i < 5; ++i) - racingCar.move(); - - - String actual = racingCar.getResultString(5); - String expected = new String(new char[racingCar.getScore()]).replace("\0", "-"); - - assertThat(actual).isEqualTo(expected); - } - - @Nested - @DisplayName("자동차 게임 설정 테스트") - class SetRacingCarGameTest { - @Test - @DisplayName("자동차 이름 입력이 하나일 경우 테스트") - void setGameWithLessThanTwoNameInput() { - RacingCarGame racingCarGame = new RacingCarGame(); - System.setIn(new ByteArrayInputStream("test1\n1".getBytes())); - - assertThatThrownBy(racingCarGame::setGame).isInstanceOf(InputMismatchException.class).hasMessage("최소한 두 명 이상의 플레이어가 필요합니다."); - } - - @Test - @DisplayName("시도할 횟수 입력이 음수일 경우 테스트") - void setGameWithNegativePhaseInput() { - RacingCarGame racingCarGame = new RacingCarGame(); - System.setIn(new ByteArrayInputStream("test1,test2\n-1\n".getBytes())); - - assertThatThrownBy(racingCarGame::setGame).isInstanceOf(NumberFormatException.class).hasMessage("음수는 유효한 숫자가 아닙니다."); - } - - @Test - @DisplayName("시도할 횟수 입력이 숫자가 아닌 경우 테스트") - void setGameWithInvalidPhaseInput() { - RacingCarGame racingCarGame = new RacingCarGame(); - System.setIn(new ByteArrayInputStream("test1,test2\nabc\n".getBytes())); - - assertThatThrownBy(racingCarGame::setGame).isInstanceOf(InputMismatchException.class).hasMessage("유효한 숫자가 아닙니다."); + void moveConditionException(int value) { + NumberGenerateUtil numberGenerateUtil = mock(NumberGenerateUtil.class); + when(numberGenerateUtil.generateRandomNumber()).thenReturn(value); + RacingCarDao racingCarDao = new RacingCarDao(); + RacingCarService racingCarService = new RacingCarServiceImpl(racingCarDao, numberGenerateUtil); + List racingCarCreateDtoList = Stream.of("tester1", "tester2").map(v -> RacingCarConverter.toRacingCarCreateDto("")).toList(); + racingCarService.createRacingCar(racingCarCreateDtoList); + + assertThatThrownBy(racingCarService::move).isInstanceOf(NumberFormatException.class).hasMessage("0~9 사이의 Power 값을 필요로 합니다."); } } } diff --git a/src/test/java/RacingCarViewTest.java b/src/test/java/RacingCarViewTest.java new file mode 100644 index 00000000..e04f2eae --- /dev/null +++ b/src/test/java/RacingCarViewTest.java @@ -0,0 +1,64 @@ +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.ByteArrayInputStream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import view.RacingCarView; +import view.RacingCarView.RacingCarInputException; + +public class RacingCarViewTest { + + @Nested + class InputRacingCarNameTest { + @Test + @DisplayName("자동차 이름 입력이 하나일 경우 테스트") + void inputWithLessThanTwoName() { + RacingCarView racingCarView = new RacingCarView(); + System.setIn(new ByteArrayInputStream("test1\n".getBytes())); + + assertThatThrownBy(racingCarView::inputRacingCarName).isInstanceOf(RacingCarInputException.class).hasMessage("최소한 두 명 이상의 플레이어가 필요합니다."); + } + + @Test + @DisplayName("자동차 이름에 띄어쓰기가 있을 경우 테스트") + void inputWithSpace() { + RacingCarView racingCarView = new RacingCarView(); + System.setIn(new ByteArrayInputStream("test1, test2\n".getBytes())); + + assertThat(racingCarView.inputRacingCarName().stream().noneMatch(s -> s.contains(" "))).isTrue(); + } + + @Test + @DisplayName("자동차 이름에 특수기호 있을 경우 테스트") + void inputWithSpecialSymbol() { + RacingCarView racingCarView = new RacingCarView(); + System.setIn(new ByteArrayInputStream("test1#,test2&\n".getBytes())); + + assertThatThrownBy(racingCarView::inputRacingCarName).isInstanceOf(RacingCarInputException.class).hasMessage("이름에 특수기호를 입력할 수 없습니다."); + } + } + + @Nested + class InputRoundTest { + @Test + @DisplayName("시도할 횟수 입력이 음수일 경우 테스트") + void inputWithNegativeNumber() { + RacingCarView racingCarView = new RacingCarView(); + System.setIn(new ByteArrayInputStream("-1\n".getBytes())); + + assertThatThrownBy(racingCarView::inputRound).isInstanceOf(RacingCarInputException.class).hasMessage("횟수는 1회 이상이여야 합니다."); + } + + @Test + @DisplayName("시도할 횟수 입력이 숫자가 아닌 경우 테스트") + void inputWithInvalidCharacter() { + RacingCarView racingCarView = new RacingCarView(); + System.setIn(new ByteArrayInputStream("abc\n".getBytes())); + + assertThatThrownBy(racingCarView::inputRound).isInstanceOf(RacingCarInputException.class).hasMessage("유효하지 않은 입력입니다."); + } + } + +}