Skip to content

[자동차 경주] 임아리 미션 제출합니다. #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
950bdc3
레이싱카 파일 추가
dldb-chamchi Feb 3, 2025
c1e2668
초기 세팅
dldb-chamchi Feb 3, 2025
b298a02
RacingCar 생성자 설정
dldb-chamchi Feb 3, 2025
35639ee
game 파일 추가
dldb-chamchi Feb 3, 2025
ec5522b
main을 통한 레이싱 카 테스트
dldb-chamchi Feb 3, 2025
4a90a8c
실행 횟수 입력 메소드 예외 기능 추가
dldb-chamchi Feb 4, 2025
50e86c5
레이싱카 이름 설정
dldb-chamchi Feb 4, 2025
180a59c
레이싱 카 생성 기능 추가
dldb-chamchi Feb 4, 2025
4a6f1d4
랜덤숫자 기능 추가 및 예외처리 추가
dldb-chamchi Feb 4, 2025
4a79ae4
레이싱 카가 갈 수 있는지 확인 하능 기능 추가
dldb-chamchi Feb 4, 2025
75f0bfa
실행 횟수 멤버변수로 변경
dldb-chamchi Feb 4, 2025
83853e0
게임 과정 출력 기능 추가
dldb-chamchi Feb 4, 2025
effa166
생성자 초기화 수정
dldb-chamchi Feb 4, 2025
fdb9e3f
게임 과정 출력 기능 완료
dldb-chamchi Feb 4, 2025
a483534
메소드 내용 수정
dldb-chamchi Feb 5, 2025
7964514
randomPick 메소드 수정
dldb-chamchi Feb 7, 2025
52bee52
게임 실행 결과 출력 완성
dldb-chamchi Feb 7, 2025
56ec7b7
접근권한 수정
dldb-chamchi Feb 7, 2025
f224241
main을 통한 테스트
dldb-chamchi Feb 7, 2025
de37998
테스트 파일 생성
dldb-chamchi Feb 7, 2025
7bcc025
리팩터링 시작
dldb-chamchi Feb 8, 2025
016d504
RacingGame 완성
dldb-chamchi Feb 8, 2025
bdc7653
view 완성
dldb-chamchi Feb 8, 2025
697dfc2
controller 완성
dldb-chamchi Feb 8, 2025
eff3d6e
테스트
dldb-chamchi Feb 8, 2025
20e80ad
테스트 완료
dldb-chamchi Feb 9, 2025
3aadaa1
피드백 반영
dldb-chamchi Feb 15, 2025
001cf15
feat: 테스트 케이스 추가
dldb-chamchi Feb 15, 2025
96678d5
fix: View -> input & output 분리
dldb-chamchi Feb 15, 2025
5b1d69f
리팩터링
dldb-chamchi Feb 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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')
testImplementation('org.mockito:mockito-core:5.7.0')
testImplementation 'org.mockito:mockito-junit-jupiter:5.7.0'
}

test {
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/GameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
public class GameController {
private final RacingGame game;
private final InputView inputView;
private final OutputView outputView;

public GameController(RacingGame game, InputView inputView, OutputView outputView){
this.game = game;
this.inputView = inputView;
this.outputView = outputView;
}

public void startGame() {
String[] carNames = inputView.inputCarName().split(",");
int runCount = inputView.inputRunCount();

game.initializeGame(carNames, runCount);
outputView.printGameStart();

for (int i = 0; i < game.getRunCount(); ++i) {
game.playRound();
outputView.printRound(game.getRacingCars());
}

outputView.printWinner(game.findWinners());
}
}
29 changes: 29 additions & 0 deletions src/main/java/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import java.util.Scanner;

public class InputView {
static Scanner in = new Scanner(System.in);

public String inputCarName(){
System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).");
String carName = in.nextLine();
if(carName == null || carName.isEmpty()) throw new RuntimeException("자동차 이름을 제대로 입력해주세요.");
return carName;
}

public int inputRunCount(){
System.out.println("시도할 횟수는 몇 회인가요?");
int runCount;
try{
runCount = in.nextInt();
runCountMinusCheck(runCount);
}
catch (NumberFormatException e) {
throw new RuntimeException("정수만 가능합니다.");
}
return runCount;
}

private void runCountMinusCheck(int runCount){
if(runCount <= 0) throw new RuntimeException("실행횟수가 0이하 입니다.");
}
}
19 changes: 19 additions & 0 deletions src/main/java/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import java.util.List;

public class OutputView {

public void printGameStart() {
System.out.println("\n실행 결과");
}

public void printRound(List<RacingCar> racingCars) {
for (RacingCar car : racingCars) {
System.out.println(car.getCarName() + " : " + "-".repeat(car.getForwardCount()));
}
System.out.println();
}

public void printWinner(List<String> winnerCars){
System.out.printf("최종 우승자 : %s%n", String.join(", ", winnerCars));
}
}
21 changes: 21 additions & 0 deletions src/main/java/RacingCar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
public class RacingCar {
private final String carName;
private int forwardCount = 0;
RacingCar(String carName){
if(carName == null || carName.isEmpty()) throw new RuntimeException("제대로된 자동차 이름을 입력해주세요.");
if(carName.length() > 5) throw new RuntimeException("자동차 이름은 5자 이하로 설정해주세요.");
this.carName = carName;
}

public String getCarName(){
return carName;
}

public void move(int randomNumber){
if(randomNumber >= 4) ++forwardCount;
}

public int getForwardCount(){
return forwardCount;
}
}
52 changes: 52 additions & 0 deletions src/main/java/RacingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class RacingGame {
private final List<RacingCar> racingCars = new ArrayList<>();
private final Random random;
private int runCount;

public RacingGame(Random random){
this.random = random;
}
Comment on lines +10 to +12

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 생성자를 이용해서 초기화 해주는 방식을 이용하면 의존성 주입을 해줄 수 있습니다!
테스트에서는 요 Random을 테스트의 입맞에 맞게 넣어주면 되겠죠??
방법은 어려가지가 있을 수 있겠지만 현재 짜여진 코드를 바꾸지 않고 원하는 랜덤값으로 테스트를 해보려면 다음과 같은 방법이 있을 것 같아요!

  1. Random을 상속하는 mockRandom을 만든다.
  2. nextInt()함수를 재정의 한다. 이때 함수의 반환값은 nextInt의 인자를 그대로 반환한다.
  3. 테스트에서는 RacingGame을 생성할 때 mockRandom을 이용하여 초기화 한다.
public class MockRandom extends Random {

    private int value = 0;

    public void setRandom(int value) {
        this.value = value;
    }

    @Override
    public int nextInt(int bound) {
        return value;
    }
}
@Test
    void 자동차_전진_테스트() {
        MockRandom mockRandom = new MockRandom();
        RacingGame game = new RacingGame(mockRandom);
        mockRandom.setRandom(4); // 랜덤값이 4만 뜨게 설정
        .
        .
        .
    }

아리님의 코드를 수정하지 않고 랜덤값을 테스트 하기 위해서 상속을 사용했지만, interface를 활용할 수 도 있답니다. 이부분에 대해서는 추가적으로 학습해 보시면 좋을 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다! mock이 정확히 무엇인지 이해하지 못했는데 많은 도움이 됐습니다! 알려주신 내용 참고하여 학습해보겠습니다!


public void initializeGame(String[] carNames, int runCount) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initializeGame은 생성자의 역할에 가까운 것 같습니다!

setRunCount, joinCars와 같은 함수로 분리해보는건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조언해주셔서 감사합니다! 참고하여 적용해보겠습니다 ㅎㅎ

this.runCount = runCount;
for (String name : carNames) {
racingCars.add(new RacingCar(name));
}
}

public void playRound() {
for (RacingCar car : racingCars) {
car.move(random.nextInt(10));
}
}

public int getRunCount() {
return runCount;
}

public List<RacingCar> getRacingCars() {
return racingCars;
}

public List<String> findWinners() {
int maxPosition = racingCars.stream()
.mapToInt(RacingCar::getForwardCount)
.max()
.orElse(0);
List<String> winners = new ArrayList<>();
for (RacingCar car : racingCars) {
if (checkWinner(car, maxPosition)) {
winners.add(car.getCarName());
}
}
return winners;
}

private boolean checkWinner(RacingCar car, int maxPosition){
return car.getForwardCount() == maxPosition;
}
}
52 changes: 52 additions & 0 deletions src/test/java/GameTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.*;

@ExtendWith(MockitoExtension.class)
class GameTest {
@Test
void 자동차_전진_테스트() {
RacingGame game = new RacingGame(new Random());
game.initializeGame(new String[]{"neo", "brie"}, 5);

RacingCar neo = game.getRacingCars().get(0);
neo.move(4);
assertEquals(1, neo.getForwardCount());

neo.move(3);
assertEquals(1, neo.getForwardCount());
}

@Test
void 우승자_선택_테스트() {
RacingGame game = new RacingGame(new Random());
game.initializeGame(new String[]{"neo", "brie"}, 5);

game.getRacingCars().get(0).move(5);
game.getRacingCars().get(1).move(3);

List<String> winners = game.findWinners();
assertEquals(Collections.singletonList("neo"), winners);
}

@Test
void 랜덤_전진_테스트() {
Random mockRandom = mock(Random.class);
when(mockRandom.nextInt(10)).thenReturn(4, 2, 7, 8, 3);

RacingGame game = new RacingGame(mockRandom);
game.initializeGame(new String[]{"pobi", "crong"}, 5);

game.playRound(); // 1라운드 실행
assertEquals(1, game.getRacingCars().get(0).getForwardCount());
assertEquals(0, game.getRacingCars().get(1).getForwardCount());

game.playRound();
assertEquals(2, game.getRacingCars().get(0).getForwardCount());
assertEquals(1, game.getRacingCars().get(1).getForwardCount());
}
}