Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
fbfab99
Git -commit feat:1주차 과제(서현진)
Sep 11, 2025
1c54f83
Git -commit feat:1주차 과제(서현진)
Sep 11, 2025
dee665e
Git -commit feat: 하드코딩 수정
Sep 12, 2025
a9af148
Git -commit feat: RaceSetting 클래스 생성
Sep 12, 2025
c6d9acc
feat: Race,RaceSetting 클래스 생성
Sep 13, 2025
560ac39
feat: RaceWinner 클래스 생성
Sep 13, 2025
aeb4ab7
feat: setMoveCnt 메소드 생성
Sep 13, 2025
dcb4ec5
feat : 전체적인 코드 수정 및 구조 변경 ( Car, Race, RaceSetting, RaceWinner)
Sep 13, 2025
c11d098
feat : RaceSetting,RaceWinner 클래스 수정
Sep 13, 2025
480f751
feat : depth 2 이상 수정
Sep 13, 2025
c0d037a
feat : README 수정
Sep 13, 2025
62b3941
feat : README 수정2
Sep 13, 2025
864e6c0
feat : mvc 패턴 적용 - Car클래스 수정
Sep 15, 2025
97b4d95
feat : mvc 패턴 적용 - 새로운 클래스 'Cars'
Sep 15, 2025
035ecdd
feat : mvc 패턴 적용 - 새로운 클래스 'InputView'
Sep 15, 2025
0de29df
feat : mvc 패턴 적용 - 새로운 클래스 'OutputView'
Sep 15, 2025
f660a28
feat : mvc 패턴 적용 - 새로운 클래스 'RacingCController'
Sep 15, 2025
7f5f429
feat : mvc 패턴 적용 - 새로운 클래스 'Application'
Sep 15, 2025
630df3a
feat : EOF 관련 수정
Sep 15, 2025
22dc5a0
feat : 첫 커밋
Sep 16, 2025
704cf09
feat : 3,4단계 구현
Sep 18, 2025
c19c73a
feat : GenerateRandom의 반환 값을 boolean으로 변경 및 car클래스에서 random 메소드 제거
Sep 18, 2025
b608f5b
feat : GenerateRandom의 반환 값을 boolean으로 변경 및 car클래스에서 random 메소드 제거 2
Sep 18, 2025
b471111
feat : cars에 moveAll을 move로 변경
Sep 18, 2025
cd70b8a
feat : new function 'isValid' in InputView
Sep 18, 2025
66e64b6
Delete src/main/java/CarMain.java
nonactress Sep 18, 2025
68814e7
Delete src/main/java/Race.java
nonactress Sep 18, 2025
4f1b377
Delete src/main/java/RaceSetting.java
nonactress Sep 18, 2025
ced1092
Delete src/main/java/RaceWinner.java
nonactress Sep 18, 2025
fd0a317
feat : generate package
Sep 19, 2025
76330fc
깃 작동 여부 확인
Sep 19, 2025
03ef929
refactor(random): Improve name of random generation logic
Sep 19, 2025
3e12240
refactor(random): making 'RacingService'and refactoring 'RacingContro…
Sep 19, 2025
cd944bc
refactor(controller): making 'RacingService'and refactoring 'RacingCo…
Sep 19, 2025
5ca9b26
refactor(model): constructor 'car' delete
Sep 19, 2025
fb563ce
refactor(model): 'isFindingFirstPizes'changes to 'checkAndAddWinner'
Sep 19, 2025
482cf13
refactor(view): method 'PrintCarPostion' rogic
Sep 19, 2025
d5ef197
Merge branch 'hyeonjin-2' of https://github.com/nonactress/java-racin…
Sep 19, 2025
ad763d8
refactor(input): method 'getCarNames' rogic
Sep 19, 2025
cab4c5f
refactor(input): renaming about Random package
Sep 20, 2025
b160676
feat : RandomMoveStrategyTest
Sep 20, 2025
2831966
feat : isValid over 2 depth
Sep 20, 2025
ada34f1
feat (CarsWinner) : new class 'CarWinner'
Sep 22, 2025
eb25bf2
feat (Test) : delete 'Racing ControllerTest'
Sep 22, 2025
c2e519f
refactor (input) : change rogic 'getCarName'
Sep 22, 2025
43190b6
refactor (model,controller) : new class 'Carwinner'2
Sep 22, 2025
f6c6e25
refactor (view) :apply 'try-catch' rogic
Sep 22, 2025
3fb578e
refactor (view) : making Random rogic
Sep 24, 2025
7d22b1d
refactor (Number) : making Package 'Number'
Sep 24, 2025
72497ef
refactor (Number) : making 'FixedNumberGenerator'
Sep 24, 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
File renamed without changes.
8 changes: 8 additions & 0 deletions src/main/java/RacingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import controller.RacingController;

public class RacingGame {
public static void main(String[] args) {
RacingController racingController = new RacingController();
racingController.run();
}
}
23 changes: 23 additions & 0 deletions src/main/java/controller/RacingController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package controller;

import model.Cars;
import model.CarsWinner;
import view.InputView;
import view.OutputView;


public class RacingController {
public void run() {
String[] carNames = InputView.getCarNames();
int raceCount = InputView.getRaceCount();

Cars cars = new Cars(carNames);
CarsWinner carsWinner = new CarsWinner();

OutputView.printResultMessage();
RacingService racingService = new RacingService();
racingService.startRace(cars, raceCount);

OutputView.printWinners(carsWinner.findWinners(cars));
}
}
19 changes: 19 additions & 0 deletions src/main/java/controller/RacingService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package controller;

import model.Cars;
import model.CarsWinner;
import model.Number.IsMovable;
import view.OutputView;

public class RacingService {
public void startRace(Cars cars, int raceCount) {
IsMovable isMovable = new IsMovable();
CarsWinner carsWinner = new CarsWinner();

for (int i = 0; i < raceCount; i++) {
cars.moveAll(isMovable); // Model의 상태 변경 요청
OutputView.printRoundResult(cars.getCars()); // View에 출력 요청
}
carsWinner.findWinners(cars);
}
}
27 changes: 27 additions & 0 deletions src/main/java/model/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package model;

import java.util.ArrayList;

public class Car {

private final String name;
private int position = 0;

public Car(String name) {
this.name = name;
}

public void move() {
this.position++;
}

public String getName() {
return name;
}

public int getPosition() {
return position;
}
}


39 changes: 39 additions & 0 deletions src/main/java/model/Cars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import model.Number.IsMovable;

public class Cars {
private final List<Car> cars;

public Cars(String[] carNames) {
this.cars = new ArrayList<>();
for (String name : carNames) {
cars.add(new Car(name));
}
}

public void moveAll(IsMovable isMovable) {
for (Car car : cars) {
move(car, isMovable);
}
}

private void move(Car car, IsMovable isMovable) {
if (isMovable.getcheck()) {
car.move();
}
}

public List<Car> getCars() {
return Collections.unmodifiableList(cars);

/*return this.cars;
*위 방식을 안쓴 이유는 객체를 받아서 다른 메소드나 클래스에서
*수정이 가능해 지기 때문에 위 컬렉션 메소드로 반환값 설정
* */
}
}
32 changes: 32 additions & 0 deletions src/main/java/model/CarsWinner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package model;


import java.util.ArrayList;
import java.util.List;

public class CarsWinner {
private final List<String> winners = new ArrayList<>();


public List<String> findWinners(Cars cars) {
int maxPosition = findMaxPosition(cars);
for (Car car : cars.getCars()) {
checkAndAddWinner(winners, car, maxPosition);
}
return winners;
}

private void checkAndAddWinner(List<String> winners, Car car, int maxPosition) {
if (car.getPosition() == maxPosition) {
winners.add(car.getName());
}
}

private int findMaxPosition(Cars cars) {
int maxPosition = 0;
for (Car car : cars.getCars()) {
maxPosition = Math.max(car.getPosition(), maxPosition);
}
return maxPosition;
}
}
10 changes: 10 additions & 0 deletions src/main/java/model/Number/FixedNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package model.Number;

public class FixedNumberGenerator implements NumberGenerator {
private static final int NOT_MOVE_CONITION = 1;

@Override
public int genrator() {
return NOT_MOVE_CONITION;
}
}
15 changes: 15 additions & 0 deletions src/main/java/model/Number/IsMovable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package model.Number;

public class IsMovable {
private NumberGenerator movable = new RandomNumberGenerator();
private NumberGenerator notNovable = new FixedNumberGenerator();

private static final int MOVE_CONITION = 4;

public Boolean getcheck() {
//return movable.genrator() > MOVE_CONITION;
return notNovable.genrator() > MOVE_CONITION;
}


}
5 changes: 5 additions & 0 deletions src/main/java/model/Number/NumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package model.Number;

public interface NumberGenerator {
int genrator();
}
13 changes: 13 additions & 0 deletions src/main/java/model/Number/RandomNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package model.Number;

import java.util.Random;

public class RandomNumberGenerator implements NumberGenerator {

@Override
public int genrator()
{
final Random random = new Random();
return random.nextInt(10);
}
}
55 changes: 55 additions & 0 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package view;

import java.util.Scanner;

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

public static String[] getCarNames() {
String[] splits = null;
boolean splitsCheck = false;
while (true) {
try {
System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
splits = scanner.nextLine().split(",", -1);

// 예외가 발생할 수 있는 검증 메서드를 호출
splitsCheck = isValid(splits);
} catch (IllegalArgumentException e) {
// validateCarNames에서 예외를 던지면 이 코드가 실행됨
// 예외에 담긴 메시지를 출력하고, while 루프의 처음으로 돌아감
System.out.println(e.getMessage());
}
if (splits != null && splitsCheck) return splits;
}
}

private static String[] getStrings(String[] splitCar) {
if (isValid(splitCar)) {
return splitCar;
}
return null;
}

public static int getRaceCount() {
System.out.println("시도할 회수는 몇회인가요?");
int count = scanner.nextInt();
scanner.nextLine(); // 개행 문자 제거
return count;
}

public static boolean isValid(String[] cars) {
if (cars.length <= 1) {
// boolean을 반환하는 대신, 예외를 생성하고 던집니다.
throw new IllegalArgumentException("[ERROR] 두 개 이상의 자동차를 입력해주세요!");
}

for (String car : cars) {
if (car.trim().isEmpty()) {
System.out.println("자동차의 이름이 공백일 순 없습니다!");
return false;
}
}
return true;
}
}
30 changes: 30 additions & 0 deletions src/main/java/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package view;

import model.Car;

import java.util.List;

public class OutputView {

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

public static void printRoundResult(List<Car> cars) {
for (Car car : cars) {
System.out.print(car.getName() + " : ");
printCarPosition(car);
System.out.println();
}
System.out.println();
}

private static void printCarPosition(Car car) {
System.out.print("-".repeat(car.getPosition()));
}

public static void printWinners(List<String> winners) {
String winnerNames = String.join(", ", winners);
System.out.println("최종 우승자 : " + winnerNames);
}
}
51 changes: 51 additions & 0 deletions src/test/java/model/CarTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package model;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CarTest {

@Test
@DisplayName("자동차 생성 시 이름과 초기 위치(0)를 올바르게 설정한다.")
void createCar() {
// given: "pobi"라는 이름을 가진 자동차를 준비하고
String carName = "pobi";

// when: 해당 이름으로 자동차를 생성하면
Car car = new Car(carName);

// then: 이름은 "pobi"이고 위치는 0이어야 한다.
assertEquals(carName, car.getName());
assertEquals(0, car.getPosition());
}

@Test
@DisplayName("move 메서드를 호출하면 위치가 1 증가한다.")
void moveCar() {
// given: "woni"라는 이름의 자동차를 생성하고
Car car = new Car("woni");

// when: move 메서드를 한 번 호출하면
car.move();

// then: 자동차의 위치는 1이 되어야 한다.
assertEquals(1, car.getPosition());
}

@Test
@DisplayName("move 메서드를 여러 번 호출하면 호출한 횟수만큼 위치가 증가한다.")
void moveCarMultipleTimes() {
// given: "jun"이라는 이름의 자동차를 생성하고
Car car = new Car("jun");
int moveCount = 5;

// when: move 메서드를 5번 호출하면
for (int i = 0; i < moveCount; i++) {
car.move();
}

// then: 자동차의 위치는 5가 되어야 한다.
assertEquals(moveCount, car.getPosition());
}
}

Choose a reason for hiding this comment

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

give-when-then으로 테스트 잘 작성해주셨네요 👍
@DisplayName 대신 한국어로 테스트 이름을 바로 지을 수도 있어요!

void move_메서드를_호출하면_위치가_1_증가한다() 

19 changes: 19 additions & 0 deletions src/test/java/model/random/RandomMoveStrategyTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package model.random;

import model.random.*;
import model.Car;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class RandomMoveStrategyTest {

@Test
@DisplayName("값이 랜덤한지 확인")
void checkRandom (){
// given: "pobi"라는 이름을 가진 자동차를 준비하고
String carName = "pobi";

Choose a reason for hiding this comment

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

이 테스트가 어떤 걸 테스트하고 싶은지 잘 모르겠습니다! 실제로 랜덤한 값이 나오는 것을 테스트하고 싶으신 건가요?? 만약 그렇다면, 그건 저희가 직접 테스트하기 아주 어려운 영역이라고 생각합니다. '진짜 랜덤'은 테스트를 실행할 때마다 결과가 계속 바뀌기 때문에, 결과를 예측하고 검증하는 자동화된 테스트를 만들기 거의 불가능하기 때문입니다. 이건 저희 코드의 로직보다는 Java의 Random 클래스 자체의 기능을 테스트하는 셈이라 테스트하지 않아도 되는 영역 같습니다!

Copy link
Author

Choose a reason for hiding this comment

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

아아 위 코드를 작성한 이유는 만약에 제가 RandomGenerator를 만들지 않았다면 랜덤한 값이 나오는 메소드인지 확인해보지 않을까?? 하는 생각에서 작성한 코드 였습니다!
만약 지금은 프로젝트의 단위가 작지만 커진다면 위와 같이 자신이 작성하지 않은 코드를 사용할 때 랜덤값이 아니여도 확인해야하는 경우도 있는지 궁금합니다!

Choose a reason for hiding this comment

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

결론부터 말씀드리면, 프로젝트 규모가 아무리 커져도 java.util.Random과 같은 외부 표준 라이브러리가 정말 랜덤한 값을 생성하는지 직접 테스트하는 경우는 거의 없는 것 같습니다.

이유를 크게 두 가지로 생각해봤는데요,

  1. 신뢰와 책임의 범위
    Java의 표준 라이브러리처럼 엄청 많은 개발자가 사용하는 도구는 이미 오랜 시간에 걸쳐 검증되었다고 생각합니다! 만약 저희가 자동차 회사라고 생각해봤을 때, 저희의 책임은 타이어나 이외의 자동차 부품들을 검증하는 것이 아니라, 이 부품들을 가져와서 우리가 만든 자동차가 잘 달리게 하는 것이 아닐까요? 그래서 저희는 직접 작성한 코드의 로직을 테스트하는 데 집중하는 것이 더 효율적이라고 생각합니다.
  2. 테스트의 목적
    저희가 진짜 테스트하고 싶은 것은 랜덤 값 그 자체가 아니라, '랜덤 값을 사용하는 우리 코드가 예상대로 잘 동작하는가' 일 것 같아요!

저희는 외부 라이브러리의 기능 자체를 검증하기보다는 '그 라이브러리를 사용하는 우리 코드가 생각대로 잘 동작하는가'에 집중하는 것이 일반적인 테스트 전략인 것 같아요!

덕분에 테스트의 역할과 범위에 대해 다시 한 번 생각해볼 수 있었네요. 좋은 질문 감사합니다! 😊

}

}