diff --git a/.gitignore b/.gitignore index 249cf086af..efbdf05078 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ out/ ### VS Code ### .vscode/ +.DS_Store diff --git a/README.md b/README.md index c550c4c2a0..47faa50d80 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,134 @@ -# 자동차 경주 게임 -## 진행 방법 -* 자동차 경주 게임 요구사항을 파악한다. -* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다. -* 코드 리뷰 피드백에 대한 개선 작업을 하고 다시 PUSH한다. -* 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다. - -## 온라인 코드 리뷰 과정 -* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview) \ No newline at end of file +# 자동차 경주 게임 - Step2 + +--- + +## Step2 구현 기능 목록 (요구사항 기반) + +- 자동차 이름 입력 + - 쉼표(,) 기준으로 이름을 구분한다. + - 각 자동차에 이름을 부여한다. + - 자동차 이름은 5글자 초과 불가 (예외 발생) + +- 실행 결과 출력 + - 라운드별 전진 결과 출력 시 자동차 **이름과 전진 표시**를 함께 출력한다. + +- 최종 우승자 출력 + - 가장 멀리 간 자동차(들)를 우승자로 출력한다. + - 동점일 경우 우승자를 모두 출력한다. + +--- + +## 패키지/클래스별 구현 내용 (작업 목록) + +### 1) 실행/흐름 제어 + +#### `carrace.Application` +- 애플리케이션 시작 지점 +- 입력 → 레이스 진행 → 결과 출력까지의 전체 흐름을 연결한다. + +#### `carrace.controller.RaceGame` +- 게임 진행(컨트롤) 책임 +- 입력값을 받아 도메인 객체를 생성하고, 레이스를 수행한 뒤 출력 뷰로 결과를 전달한다. + +--- + +### 2) 도메인 - 자동차 + +#### `carrace.domain.car.Car` +- **자동차 한 대의 상태(위치)와 행위(이동)**를 관리한다. +- `Car(String carName)` + - 자동차 생성 시 이름을 검증한다. + - **이름이 5글자 초과면 `IllegalArgumentException` 발생** (유효하지 않은 자동차는 생성되지 않도록 도메인 불변조건 보장) +- `move(MoveCondition condition)` + - 이동 조건이 참이면 위치를 한 칸 전진시킨다. +- `getPosition()` + - 현재 위치 값을 반환한다. +- `getCarName()` + - 자동차 이름을 반환한다. + +#### `carrace.domain.car.CarCreator` +- 입력(문자열)로부터 자동차 목록을 생성하는 책임 +- 쉼표로 구분된 이름들을 기반으로 `Car` 객체들을 생성한다. +- (이름 trim/분리 등 “생성에 필요한 전처리”가 있다면 이 클래스에서 수행) + +--- + +### 3) 도메인 - 레이스 + +#### `carrace.domain.race.Race` +- **자동차 목록을 가지고 레이스 진행/우승자 계산**을 담당한다. +- 라운드 진행 결과를 기반으로 최종 우승자를 계산한다. +- 동점(여러 명 우승) 상황을 고려해 우승자 목록을 반환/출력할 수 있도록 구현한다. + +--- + +### 4) 서비스 - 입력 처리 + +#### `carrace.service.InputService` +- `CarRaceInputView`로부터 입력을 읽어오고, 숫자 변환 및 기본 검증을 수행한다. +- `readCarNames()` + - 자동차 이름 입력을 받는다. + - 쉼표 기준으로 분리 후 각 요소를 trim 처리한다. + - 빈 이름이 포함되면 예외를 발생시킨다. +- `readCarCount()` + - 자동차 대수 입력을 숫자로 파싱한다. + - 숫자가 아니면 예외를 발생시킨다. + - 1 미만이면 예외를 발생시킨다. +- `readRounds()` + - 시도 횟수 입력을 숫자로 파싱한다. + - 숫자가 아니면 예외를 발생시킨다. + - 1 미만이면 예외를 발생시킨다. + +--- + +### 5) View - 입출력 + +#### `carrace.view.CarRaceInputView` +- 사용자 입력을 담당한다. +- 자동차 이름 / 자동차 대수 / 시도 횟수를 입력받는다. + +#### `carrace.view.CarRaceOutputView` +- 실행 결과 출력을 담당한다. +- 라운드별 실행 결과를 자동차 이름과 함께 출력한다. +- 최종 우승자를 출력한다(동점자 포함). + +--- + +## 테스트 목록 (클래스별 / 검증 로직 설명) + +### 1) 자동차 도메인 테스트 + +#### `src/test/java/carrace/domain/car/CarTest` +- 자동차의 이동 로직이 조건에 따라 정확히 동작하는지 검증한다. +- 자동차 이름 제약(5글자 초과 불가) 검증을 테스트한다. + +#### `src/test/java/carrace/domain/car/CarCreatorTest` +- 쉼표로 구분된 자동차 이름 입력이 자동차 객체 목록으로 정상 생성되는지 검증한다. +- 이름 trim/분리 로직이 기대한 대로 동작하는지 검증한다. + +--- + +### 2) 레이스 도메인 테스트 + +#### `src/test/java/carrace/domain/race/RaceTest` +- 우승자가 1명인 경우 우승자 계산이 정확한지 검증한다. +- 동점(우승자 다수) 상황에서 우승자들이 모두 반환/출력 대상이 되는지 검증한다. + +--- + +### 3) 입력 처리 테스트 + +#### `src/test/java/carrace/service/InputServiceTest` +- 자동차 대수/시도 횟수 입력의 숫자 파싱 및 범위(1 이상) 검증을 테스트한다. +- 자동차 이름 입력의 기본 검증(빈 값/구분자 처리)이 정상 동작하는지 검증한다. + +--- + +### 4) 테스트 유틸 + +#### `src/test/java/carrace/fixture/CarsFixture` +- 테스트에서 사용할 자동차 목록/상태를 쉽게 만들기 위한 픽스처 제공 + +#### `src/test/java/carrace/fixture/StubInputView` +- 입력 뷰를 대체하기 위한 스텁(고정 입력 제공) +- 입력 기반 테스트에서 예측 가능한 입력값을 주입하기 위해 사용 diff --git a/src/main/java/carrace/Application.java b/src/main/java/carrace/Application.java index cdcaaaaf53..37ec60f43e 100644 --- a/src/main/java/carrace/Application.java +++ b/src/main/java/carrace/Application.java @@ -1,8 +1,7 @@ package carrace; import carrace.controller.RaceGame; -import carrace.domain.car.Car; -import carrace.domain.car.CarCreator; +import carrace.domain.car.Cars; import carrace.domain.move.MoveCondition; import carrace.domain.move.RandomMoveCondition; import carrace.domain.race.Race; @@ -10,7 +9,7 @@ import carrace.view.CarRaceOutputView; import carrace.service.InputService; -import java.util.List; + @@ -21,14 +20,15 @@ public static void main(String[] args) { CarRaceOutputView outputView = new CarRaceOutputView(); InputService inputService = new InputService(inputView); - int carCount = inputService.readCarCount(); + String carName = inputService.readCarNames(); int rounds = inputService.readRounds(); - List cars = CarCreator.create(carCount); + Cars cars = Cars.from(carName); MoveCondition condition = new RandomMoveCondition(); Race race = new Race(cars); RaceGame game = new RaceGame(race, condition, outputView); game.play(rounds); + } } diff --git a/src/main/java/carrace/controller/RaceGame.java b/src/main/java/carrace/controller/RaceGame.java index 024a1359c8..44faeb53ef 100644 --- a/src/main/java/carrace/controller/RaceGame.java +++ b/src/main/java/carrace/controller/RaceGame.java @@ -23,5 +23,8 @@ public void play(int rounds) { race.moveOnce(condition); outputView.printResult(race.getCars()); } + + outputView.printWinners(race.getWinners()); } + } diff --git a/src/main/java/carrace/domain/car/Car.java b/src/main/java/carrace/domain/car/Car.java index 94dd39d795..707cc509da 100644 --- a/src/main/java/carrace/domain/car/Car.java +++ b/src/main/java/carrace/domain/car/Car.java @@ -3,8 +3,28 @@ import carrace.domain.move.MoveCondition; public class Car { + private static final int MAX_NAME_LENGTH = 5; private Position position = new Position(); + private final String carName; + + public Car(String carName) { + validateName(carName); + this.carName = carName; + } + + private void validateName(String carName) { + if (carName == null || carName.isBlank()) { + throw new IllegalArgumentException("자동 이름은 비어있을 수 없습니다."); + } + if (carName.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException("자동차 이름은 5글자를 초과할 수 없습니다."); + } + } + + public String getCarName() { + return carName; + } public void move(MoveCondition condition) { if (condition.canMove()) { diff --git a/src/main/java/carrace/domain/car/CarCreator.java b/src/main/java/carrace/domain/car/CarCreator.java deleted file mode 100644 index f47661c5e5..0000000000 --- a/src/main/java/carrace/domain/car/CarCreator.java +++ /dev/null @@ -1,13 +0,0 @@ -package carrace.domain.car; - -import java.util.List; -import java.util.stream.IntStream; - -public class CarCreator { - - public static List create(int count) { - return IntStream.range(0,count) //정수 스트림 생성, 0부터 count -1까지 숫자를 차례대로 흘려보냄, ex) count = 3, stream = 0 -> 1 -> 2 - .mapToObj(i -> new Car()) //스트림에 흐르는 각 숫자 i를 Car 객체로 변환 - .toList(); // 스트림을 List로 수집, 이 순간에만 실제 실행됨(최종 연산) - } // ex) 결과 : List cars = [new Car(), new Car(), new Car()] -} diff --git a/src/main/java/carrace/domain/car/Cars.java b/src/main/java/carrace/domain/car/Cars.java new file mode 100644 index 0000000000..f259306d3f --- /dev/null +++ b/src/main/java/carrace/domain/car/Cars.java @@ -0,0 +1,68 @@ +package carrace.domain.car; + + +import carrace.domain.move.MoveCondition; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +public class Cars { + + private final List cars; + + public Cars(List cars) { + validate(cars); + this.cars = cars; + } + + public static Cars from(String input) { + String[] names = input.split(","); + List cars = new ArrayList<>(); + + for (String name : names) { + cars.add(new Car(name.trim())); + } + return new Cars(cars); + } + + private void validate(List cars) { + if (cars.isEmpty()) { + throw new IllegalArgumentException("자동차는 최소 1대 이상이어야 합니다."); + } + validateDuplicateNames(cars); + } + + private void validateDuplicateNames(List cars) { + Set names = new HashSet<>(); + for (Car car : cars) { + if (!names.add(car.getCarName())) { + throw new IllegalArgumentException("자동차 이름은 중복될 수 없습니다."); + } + } + } + + public void moveAll(MoveCondition condition) { + cars.forEach(car -> car.move(condition)); + } + + public List getWinners() { + int maxPosition = cars.stream() + .mapToInt(Car::getPosition) + .max() + .orElse(0); + + return cars.stream() + .filter(car -> car.getPosition() == maxPosition) + .toList(); + } + + + + public List asList() { + return List.copyOf(cars); + } + +} diff --git a/src/main/java/carrace/domain/race/Race.java b/src/main/java/carrace/domain/race/Race.java index cb393f5649..71aba20ec2 100644 --- a/src/main/java/carrace/domain/race/Race.java +++ b/src/main/java/carrace/domain/race/Race.java @@ -1,28 +1,29 @@ package carrace.domain.race; import carrace.domain.car.Car; +import carrace.domain.car.Cars; import carrace.domain.move.MoveCondition; + import java.util.List; public class Race { - private final List cars; + private final Cars cars; - public Race(List cars) { + public Race(Cars cars) { this.cars = cars; } public void moveOnce(MoveCondition condition) { - for (Car car : cars) { - car.move(condition); - } + cars.moveAll(condition); } - //내부 상태 보호를 위해 자동차 목록을 그대로 반환하지 않고 - //읽기 전용 리스트(unmodifiableList)를 반환하도록 수정했습니다. public List getCars() { - return List.copyOf(cars); + return cars.asList(); } + public List getWinners() { + return cars.getWinners(); + } } diff --git a/src/main/java/carrace/service/InputService.java b/src/main/java/carrace/service/InputService.java index 195905b99e..812f1fd168 100644 --- a/src/main/java/carrace/service/InputService.java +++ b/src/main/java/carrace/service/InputService.java @@ -10,23 +10,14 @@ public InputService(CarRaceInputView inputView) { this.inputView = inputView; } - public int readCarCount() { - int value = parseInt( - inputView.readCarCount(), - "자동차 대수는 숫자여야 합니다." - ); - - if (value <= 0) { - throw new IllegalArgumentException("자동차는 1대 이상이어야 합니다."); - } - return value; + public String readCarNames() { + String input = inputView.readCarNames(); + validateCarNames(input); + return input; } public int readRounds() { - int value = parseInt( - inputView.readMoveCount(), - "시도 횟수는 숫자여야 합니다." - ); + int value = parseInt(inputView.readMoveCount()); if (value <= 0) { throw new IllegalArgumentException("시도 횟수는 1 이상이어야 합니다."); @@ -34,11 +25,20 @@ public int readRounds() { return value; } - private int parseInt(String input, String errorMessage) { - try { - return Integer.parseInt(input); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(errorMessage); + private int parseInt(String input) { + return Integer.parseInt(input); + } + + private void validateCarNames(String input) { + if (input == null || input.isBlank()) { + throw new IllegalArgumentException("자동차 이름을 입력하세요"); + } + + String[] names = input.split(","); + for (String name : names) { + if (name.trim().isBlank()) { + throw new IllegalArgumentException("자동차 이름은 공백일 수 없습니다."); + } } } } diff --git a/src/main/java/carrace/view/CarRaceInputView.java b/src/main/java/carrace/view/CarRaceInputView.java index 4d10a1815f..72c0d52119 100644 --- a/src/main/java/carrace/view/CarRaceInputView.java +++ b/src/main/java/carrace/view/CarRaceInputView.java @@ -6,8 +6,9 @@ public class CarRaceInputView { private final Scanner scanner = new Scanner(System.in); - public String readCarCount() { - System.out.println("자동차 대수는 몇 대인가요?"); + + public String readCarNames() { + System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); return scanner.nextLine(); } diff --git a/src/main/java/carrace/view/CarRaceOutputView.java b/src/main/java/carrace/view/CarRaceOutputView.java index df19efda11..2ef05d930c 100644 --- a/src/main/java/carrace/view/CarRaceOutputView.java +++ b/src/main/java/carrace/view/CarRaceOutputView.java @@ -3,6 +3,7 @@ import carrace.domain.car.Car; import java.util.List; +import java.util.stream.Collectors; public class CarRaceOutputView { @@ -13,9 +14,20 @@ public void printStartMessage() { public void printResult(List cars) { for (Car car : cars) { - System.out.println("-".repeat(car.getPosition())); + System.out.println(car.getCarName() + " : " + "-".repeat(car.getPosition())); } System.out.println(); + + } + + public void printWinners(List winners) { + String winnerNames = winners.stream() + .map(Car::getCarName) + .collect(Collectors.joining(", ")); + + System.out.println(winnerNames + "가 최종 우승했습니다."); } } + + diff --git a/src/test/java/carrace/domain/car/CarTest.java b/src/test/java/carrace/domain/car/CarTest.java index 64b2689fec..82a2735f3d 100644 --- a/src/test/java/carrace/domain/car/CarTest.java +++ b/src/test/java/carrace/domain/car/CarTest.java @@ -3,22 +3,22 @@ import carrace.fixture.MoveConditions; 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.AssertionsForClassTypes.assertThatThrownBy; public class CarTest { @Test @DisplayName("새 자동차는 기본 위치가 0") void newCar_defaultPosition_zero() { - Car car = new Car(); + Car car = new Car("kdu"); assertThat(car.getPosition()).isEqualTo(0); } @Test @DisplayName("이동 조건 충족 시 항상 위치는 1 증가") void move_alwaysMove_incrementsPosition() { - Car car = new Car(); + Car car = new Car("kdu"); car.move(MoveConditions.alwaysMove()); assertThat(car.getPosition()).isEqualTo(1); } @@ -26,7 +26,7 @@ void move_alwaysMove_incrementsPosition() { @Test @DisplayName("이동하지 않는 조건에서 자동차 위치는 그대로다") void move_neverMove_positionUnchanged() { - Car car = new Car(); + Car car = new Car("kdu"); car.move(MoveConditions.neverMove()); assertThat(car.getPosition()).isEqualTo(0); } @@ -34,9 +34,38 @@ void move_neverMove_positionUnchanged() { @Test @DisplayName("연속 이동 시 위치가 누적된다") void move_multipleTimes_positionAccumulates() { - Car car = new Car(); + Car car = new Car("kdu"); car.move(MoveConditions.alwaysMove()); car.move(MoveConditions.alwaysMove()); assertThat(car.getPosition()).isEqualTo(2); } + + @Test + @DisplayName("자동차는 이름을 가진다") + void car_has_name() { + Car car = new Car("kdu"); + assertThat(car.getCarName()).isEqualTo("kdu"); + } + + @Test + @DisplayName("이름이 5글자 초과면 예외") + void name_too_long_throws() { + assertThatThrownBy(() -> new Car("abcdef")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("이름이 null 이면 예외") + void name_null_throws() { + assertThatThrownBy(() -> new Car(null)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("이름이 공백이면 예외") + void name_blank_throws() { + assertThatThrownBy(() -> new Car(" ")) + .isInstanceOf(IllegalArgumentException.class); + } + } diff --git a/src/test/java/carrace/domain/car/CarsTest.java b/src/test/java/carrace/domain/car/CarsTest.java new file mode 100644 index 0000000000..27234cee51 --- /dev/null +++ b/src/test/java/carrace/domain/car/CarsTest.java @@ -0,0 +1,51 @@ +package carrace.domain.car; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CarsTest { + + @Test + @DisplayName("쉼표 기준으로 자동차 생성") + void createCars_byComma() { + Cars cars = Cars.from("kkk,ddd,uuu"); + + List list = cars.asList(); + assertEquals(3, list.size()); + assertEquals("kkk", list.get(0).getCarName()); + assertEquals("ddd", list.get(1).getCarName()); + assertEquals("uuu", list.get(2).getCarName()); + } + + @Test + @DisplayName("자동차 이름 앞뒤 공백 제거") + void createCars_trimNames() { + Cars cars = Cars.from(" kkk , ddd , uuu "); + + List list = cars.asList(); + assertEquals(3, list.size()); + assertEquals("kkk", list.get(0).getCarName()); + assertEquals("ddd", list.get(1).getCarName()); + assertEquals("uuu", list.get(2).getCarName()); + } + + @Test + @DisplayName("자동차가 1대도 없으면 예외 발생") + void cars_shouldNotBeEmpty() { + assertThatThrownBy(() -> Cars.from("")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("자동차 이름이 중복되면 예외 발생") + void cars_shouldNotHaveDuplicateNames() { + assertThatThrownBy(() -> Cars.from("car1,car1")) + .isInstanceOf(IllegalArgumentException.class); + } +} + diff --git a/src/test/java/carrace/domain/race/RaceTest.java b/src/test/java/carrace/domain/race/RaceTest.java index d1546c2266..e88ae3dfe1 100644 --- a/src/test/java/carrace/domain/race/RaceTest.java +++ b/src/test/java/carrace/domain/race/RaceTest.java @@ -1,11 +1,13 @@ package carrace.domain.race; import carrace.domain.car.Car; +import carrace.domain.car.Cars; import carrace.fixture.CarsFixture; import carrace.fixture.MoveConditions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; + import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -17,7 +19,7 @@ class RaceTest { @Test @DisplayName("Race는 생성시 자동차 목록을 가진다") void race_initialCars_listExists() { - List cars = CarsFixture.threeCars(); + Cars cars = CarsFixture.threeCars(); Race race = new Race(cars); assertThat(race.getCars()).hasSize(3); @@ -26,7 +28,7 @@ void race_initialCars_listExists() { @Test @DisplayName("moveOnce 호출 시 이동하지 않는 조건이면 자동차 위치는 그대로다") void moveOnce_neverMove_positionUnchanged() { - List cars = CarsFixture.threeCars(); + Cars cars = CarsFixture.threeCars(); Race race = new Race(cars); race.moveOnce(MoveConditions.neverMove()); @@ -39,16 +41,43 @@ void moveOnce_neverMove_positionUnchanged() { @Test @DisplayName("getCars 반환은 내부 리스트를 보호한다") void getCars_returnsUnmodifiableList() { - List cars = CarsFixture.threeCars(); + Cars cars = CarsFixture.threeCars(); Race race = new Race(cars); List raceCars = race.getCars(); - assertThat(raceCars).containsExactlyElementsOf(cars); - // 내부 리스트 수정 시도 시 예외 발생 확인 - assertThatThrownBy(() -> raceCars.add(new Car())) + assertThatThrownBy(() -> raceCars.add(new Car("kdu"))) .isInstanceOf(UnsupportedOperationException.class); } + + @Test + @DisplayName("우승자 1명일 때 getWinners 반환") + void getWinners_single() { + Cars cars = CarsFixture.threeCars(); + Race race = new Race(cars); + + cars.asList().get(0).move(MoveConditions.alwaysMove()); + + List winners = race.getWinners(); + assertThat(winners).hasSize(1); + assertThat(winners.get(0).getCarName()).isEqualTo("car1"); + } + + @Test + @DisplayName("우승자가 여러명일 때 getWinners 반환") + void getWinners_multiple() { + Cars cars = CarsFixture.threeCars(); + Race race = new Race(cars); + + cars.asList().get(0).move(MoveConditions.alwaysMove()); + cars.asList().get(1).move(MoveConditions.alwaysMove()); + + List winners = race.getWinners(); + + assertThat(winners).hasSize(2); + assertThat(winners).extracting(Car::getCarName) + .contains("car1", "car2"); + } } diff --git a/src/test/java/carrace/fixture/CarsFixture.java b/src/test/java/carrace/fixture/CarsFixture.java index 9daaa62acb..9ed9dfcfa4 100644 --- a/src/test/java/carrace/fixture/CarsFixture.java +++ b/src/test/java/carrace/fixture/CarsFixture.java @@ -1,19 +1,16 @@ package carrace.fixture; -import carrace.domain.car.Car; -import carrace.domain.car.CarCreator; -import java.util.List; +import carrace.domain.car.Cars; + + public class CarsFixture { - // 자동차 3대를 만드는 Fixture - public static List threeCars() { - return CarCreator.create(3); + public static Cars threeCars() { + return Cars.from("car1,car2,car3"); } - // 자동차 n대를 만드는 Fixture - public static List nCars(int n) { - return CarCreator.create(n); - } + } + diff --git a/src/test/java/carrace/fixture/StubInputView.java b/src/test/java/carrace/fixture/StubInputView.java index 79d8b4ffa2..2af5bfd7bf 100644 --- a/src/test/java/carrace/fixture/StubInputView.java +++ b/src/test/java/carrace/fixture/StubInputView.java @@ -4,10 +4,18 @@ public class StubInputView extends CarRaceInputView { + private final String carName; private final String carCount; private final String rounds; public StubInputView(String carCount, String rounds) { + this.carName = ""; + this.carCount = carCount; + this.rounds = rounds; + } + + public StubInputView(String carName, String carCount, String rounds) { + this.carName = carName; this.carCount = carCount; this.rounds = rounds; } @@ -21,4 +29,9 @@ public String readCarCount() { public String readMoveCount() { return rounds; } + + @Override + public String readCarNames() { + return carName; + } } diff --git a/src/test/java/carrace/service/InputServiceTest.java b/src/test/java/carrace/service/InputServiceTest.java index eca8e00d73..943d6d2c19 100644 --- a/src/test/java/carrace/service/InputServiceTest.java +++ b/src/test/java/carrace/service/InputServiceTest.java @@ -8,24 +8,19 @@ class InputServiceTest { - @DisplayName("자동차 수가 1이면 정상 입력 (경계값)") - @Test - void carCountOneIsValid() { - InputService service = new InputService(new StubInputView("1", "5")); - assertEquals(1, service.readCarCount()); - } - - @DisplayName("자동차 수가 0이면 예외 발생 (경계값)") - @Test - void carCountZeroThrows() { - InputService service = new InputService(new StubInputView("0", "5")); - assertThrows(IllegalArgumentException.class, service::readCarCount); - } - @DisplayName("시도 횟수가 음수면 예외 발생 (경계값)") @Test void roundsNegativeThrows() { InputService service = new InputService(new StubInputView("3", "-1")); assertThrows(IllegalArgumentException.class, service::readRounds); } + + @Test + @DisplayName("자동차 이름 공백시 예외 발생") + void carNameBlankThrows() { + StubInputView inputView = new StubInputView(" , , ", "3"); + InputService service = new InputService(inputView); + + assertThrows(IllegalArgumentException.class, service::readCarNames); + } }