-
Notifications
You must be signed in to change notification settings - Fork 1.2k
step3) 자동차 경주 게임 구현 #6040
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
base: smileeeey
Are you sure you want to change the base?
step3) 자동차 경주 게임 구현 #6040
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package exception; | ||
|
||
public class NegativeNumberException extends RuntimeException { | ||
public NegativeNumberException() { super("negative number is not allowed."); } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package racingCar; | ||
|
||
public class CarRacingGame { | ||
private final InputView inputView; | ||
private final ResultView resultView; | ||
private final NumberVerifier numberVerifier; | ||
|
||
public CarRacingGame(InputView inputView, ResultView resultView, NumberVerifier numberVerifier) { | ||
this.inputView = inputView; | ||
this.resultView = resultView; | ||
this.numberVerifier = numberVerifier; | ||
} | ||
|
||
public static void main(String[] args) { | ||
InputView inputView = new InputView(); | ||
ResultView resultView = new ResultView(); | ||
NumberVerifier numberVerifier = new NumberVerifier(); | ||
CarRacingGame game = new CarRacingGame(inputView, resultView, numberVerifier); | ||
game.startGame(); | ||
} | ||
|
||
private void startGame() { | ||
RacingCar[] cars = getParticipant(); | ||
|
||
play(cars, inputView.requestPlayCount()); | ||
} | ||
|
||
private RacingCar[] getParticipant() { | ||
int participantCount = inputView.requestParticipant(); | ||
try { | ||
validateNum(participantCount); | ||
return createRacingCars(participantCount); | ||
} catch (NumberFormatException e) { | ||
System.out.println(e.getMessage()); | ||
throw e; | ||
} | ||
} | ||
|
||
void validateNum(int num) { | ||
numberVerifier.verify(num); | ||
} | ||
|
||
RacingCar[] createRacingCars(int count) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 그냥 빈 배열을 만들어주는 것 같아요? 추가로, 특별한 이유가 없다면 배열보단 List 등의 Collection을 사용하는 걸 추천드려요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리스트는 배열보다 대략 3배의 메모리를 더 사용한다고 알고 있습니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 말씀드리기전에 먼저 .. 리스트가 3배의 메모리를 사용하는 근거가 혹시 뭘까요 ? ArrayList면 기본 배열 사이즈때문에 조금 쓸 수 있어도 사이즈 지정을 해주면 부가정보 조금을 제외하면 크게 차이 없을 것 같고 .. LinkedList면 노드 크기와 타입에 따라 가변적이라 계산이 나오기가 어려울 것 같은데.. 궁금하네요! 말씀주신대로 문제는 없고 배열도 배열의 장점이 있어 필요한 경우가 있는데요. 대부분의 경우 List가 가지는 조작의 편의성과 가독성 그리고 확장성 때문에 배열보다는 List를 사용하는게 효율적이라고 생각해서 배열을 지양하시는게 어떨까 하고 드린 의견이었구요! 이건 대답을 안주셨는데, 44번 라인 빈 배열만 만들고 속이 안채워져있는 것 같아요~ 지금 프로그램 실행하면 NPE가 나지 않나요 ? |
||
return new RacingCar[count]; | ||
} | ||
|
||
private void play(RacingCar[] cars, int count) { | ||
resultView.printResultTitle(); | ||
for (int i = 0; i < count; i++) { | ||
moveCar(cars); | ||
resultView.printPlay(cars); | ||
} | ||
} | ||
|
||
private void moveCar(RacingCar[] cars) { | ||
for (RacingCar car : cars) { | ||
car.progress(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package racingCar; | ||
|
||
import java.util.Scanner; | ||
|
||
public class InputView { | ||
private static Scanner scanner = new Scanner(System.in); | ||
int requestParticipant() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기도 접근지정자가 없네요 ~ |
||
System.out.println("자동차 대수는 몇 대 인가요?"); | ||
return Integer.parseInt(scanner.nextLine()); | ||
} | ||
|
||
int requestPlayCount() { | ||
System.out.println("시도할 회수는 몇 회 인가요?"); | ||
return Integer.parseInt(scanner.nextLine()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package racingCar; | ||
|
||
import exception.NegativeNumberException; | ||
|
||
public class NumberVerifier { | ||
void verify(int num) { | ||
if (num <= 0) { | ||
throw new NegativeNumberException(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package racingCar; | ||
|
||
public class RacingCar { | ||
private int position; | ||
private RandomNumberGenerator randomNumberGenerator; | ||
|
||
public RacingCar(int position, RandomNumberGenerator randomNumberGenerator) { | ||
this.position = position; | ||
this.randomNumberGenerator = randomNumberGenerator; | ||
} | ||
|
||
public int getPosition() { | ||
return position; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "RacingCar{" + "position=" + position + '}'; | ||
} | ||
|
||
void progress() { | ||
if (randomNumberGenerator.makeRandomNumber() >= 4){ | ||
incPosition(); | ||
} | ||
} | ||
|
||
protected void incPosition() { | ||
++this.position; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package racingCar; | ||
|
||
import java.util.Random; | ||
|
||
class RandomNumberGenerator{ | ||
final int RANDOM_NUMBER_BOUND = 10; | ||
public int makeRandomNumber() { | ||
return new Random().nextInt(RANDOM_NUMBER_BOUND); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package racingCar; | ||
|
||
public class ResultView { | ||
void printResultTitle() { | ||
System.out.println("실행 결과"); | ||
} | ||
|
||
void printPlay(RacingCar[] cars) { | ||
for (RacingCar car : cars) { | ||
System.out.println("-".repeat(car.getPosition())); | ||
} | ||
System.out.println(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package racingCar; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
class CarRacingGameTest { | ||
private CarRacingGame carRacingGame; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
InputView inputView = new InputView(); | ||
ResultView resultView = new ResultView(); | ||
NumberVerifier numberVerifier = new NumberVerifier(); | ||
carRacingGame = new CarRacingGame(inputView, resultView, numberVerifier); | ||
} | ||
|
||
@Test | ||
void testCreateRacingCars() { | ||
int TEST_COUNT = 3; | ||
RacingCar[] createdCars = carRacingGame.createRacingCars(TEST_COUNT); | ||
assertEquals(3, createdCars.length); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package racingCar; | ||
|
||
import exception.NegativeNumberException; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
public class NumberVerifierTest { | ||
|
||
@Test | ||
public void testVerify_WithPositiveNumber() { | ||
NumberVerifier verifier = new NumberVerifier(); | ||
verifier.verify(5); | ||
} | ||
|
||
@Test | ||
public void testVerify_WithZero_ShouldThrowException() { | ||
NumberVerifier verifier = new NumberVerifier(); | ||
assertThrows(NegativeNumberException.class, () -> verifier.verify(0)); | ||
} | ||
|
||
@Test | ||
public void testVerify_WithNegativeNumber_ShouldThrowException() { | ||
NumberVerifier verifier = new NumberVerifier(); | ||
assertThrows(NegativeNumberException.class, () -> verifier.verify(-1)); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package racingCar; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.Mockito.*; | ||
|
||
class RacingCarTest { | ||
|
||
private RacingCar car; | ||
RandomNumberGenerator mockGenerator = mock(RandomNumberGenerator.class); | ||
|
||
@BeforeEach | ||
void setUp() { | ||
car = spy(new RacingCar(0, mockGenerator)); | ||
} | ||
|
||
@Test | ||
void progress() { | ||
when(mockGenerator.makeRandomNumber()).thenReturn(4); | ||
int expected = car.getPosition() + 1; | ||
|
||
car.progress(); | ||
|
||
assertEquals(expected, car.getPosition()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package racingCar; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.Mockito.*; | ||
|
||
class RandomNumberGeneratorTest { | ||
@Test | ||
public void testMakeRandomNumber_WithMock() { | ||
RandomNumberGenerator mockGenerator = mock(RandomNumberGenerator.class); | ||
when(mockGenerator.makeRandomNumber()).thenReturn(4); | ||
|
||
assertEquals(4, mockGenerator.makeRandomNumber()); | ||
verify(mockGenerator).makeRandomNumber(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
접근지정자가 없는 메서드들이 있네요 ~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트코드를 위해 default 접근지정자를 사용했습니다.
private으로 두고 테스트하는 방법들을 찾아보았는데
대안으로 default 생성자를 사용하고 테스트코드에서 사용하는 방식을 사용했는데요, 다른 대안이 있다면 말씀해주세요:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트코드를 위해 접근지정자를 변경하는 등의 기존 코드에 영향을 주는건 바람직하지 못합니다!
그리고 기본적으로 테스트코드의 대상은 public이라 private 메서드를 직접 테스트하지는 않으셔도 돼요!
이건 아마 ..
모든 로직에 단위 테스트를 구현한다
라는 요구사항 때문에 말씀하신 것 같은데, 여기서 말하는 모든 로직은 public 메서드를 뜻합니다! 기본적으로는 public 메서드를 통해 내부에서 사용되는 private 메서드가 같이 검증되어야 하고, 만약 이게 어렵거나 private 메서드를 직접 테스트해야 하는 상황이 있다면 그건 클래스 설계가 잘못되지 않았는지 의심해봐야 해요