-
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 1 commit
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,62 @@ | ||
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() { | ||
while (true) { | ||
int participantCount = inputView.requestParticipant(); | ||
try { | ||
validateNum(participantCount); | ||
return createRacingCars(participantCount); | ||
} catch (NumberFormatException e) { | ||
System.out.println(e.getMessage()); | ||
throw e; | ||
} | ||
} | ||
} | ||
|
||
void validateNum(int num) { | ||
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. 접근지정자가 없는 메서드들이 있네요 ~ 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. 테스트코드를 위해 default 접근지정자를 사용했습니다.
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. 테스트코드를 위해 접근지정자를 변경하는 등의 기존 코드에 영향을 주는건 바람직하지 못합니다!
이건 아마 .. |
||
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,38 @@ | ||
package racingCar; | ||
|
||
import java.util.Random; | ||
|
||
public class RacingCar { | ||
private int pos; | ||
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. 변수명에는 줄임말을 지양해주세요 ~ |
||
|
||
public RacingCar(int pos) { | ||
this.pos = pos; | ||
} | ||
|
||
public int getPos() { | ||
return pos; | ||
} | ||
|
||
public void setPos(int pos) { | ||
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. getter/setter는 최대한 지양 해 주세요 ~ 특히 setter는 아예 안쓰시는 걸 추천드립니다! |
||
this.pos = pos; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "RacingCar{" + "pos=" + pos + '}'; | ||
} | ||
|
||
int makeRandomNum() { | ||
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. 이 역할을 RacingCar가 가지고 있어야 하는게 맞을까요 ? 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. 별도 클래스로 역할 구분했습니다~ |
||
return new Random().nextInt(10); | ||
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. 상수로 빼주시면 좋을 것 같아요 ~ |
||
} | ||
|
||
void progress() { | ||
if (makeRandomNum() >= 4){ | ||
incPos(); | ||
} | ||
} | ||
|
||
protected void incPos() { | ||
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. 요게 있는데 setter는 왜 있는걸까요 ? 그리고 이건 왜 protected인가요 ? |
||
++this.pos; | ||
} | ||
} |
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.getPos())); | ||
} | ||
System.out.println(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package racingCar; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.Mockito.mock; | ||
|
||
class CarRacingGameTest { | ||
private CarRacingGame carRacingGame; | ||
private RacingCar[] cars; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
InputView mockInputView = mock(InputView.class); | ||
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. mocking 한 객체를 아래에서 사용하지 않는것으로 보이는데요, mocking 한 이유가 있을까요 ? 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. 별다른 이유는 없어서 실제 객체를 사용하도록 변경했습니다~ |
||
ResultView mockResultView = mock(ResultView.class); | ||
NumberVerifier numberVerifier = mock(NumberVerifier.class); | ||
carRacingGame = new CarRacingGame(mockInputView, mockResultView, numberVerifier); | ||
cars = new RacingCar[3]; | ||
} | ||
|
||
@Test | ||
void testValidateNames_validNames() { | ||
int TEST_COUNT = 3; | ||
assertDoesNotThrow(() -> carRacingGame.validateNum(TEST_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. 테스트는 기본적으로 public 메서드에 대해서만 진행하고, 테스트를 위해 접근지정자 레벨을 조정하는 건 지양해야 합니다~ 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. 위에서 말씀드렸듯이.. 접근 지정자 조정보다 나은 해결책을 잘 모르겠습니다.. |
||
} | ||
|
||
@Test | ||
void testValidateNames_invalidNames() { | ||
int TEST_COUNT = 3; | ||
assertThrows(NumberFormatException.class, () -> carRacingGame.validateNum(TEST_COUNT)); | ||
} | ||
|
||
@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,37 @@ | ||
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.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.mockito.Mockito.*; | ||
|
||
class RacingCarTest { | ||
|
||
private RacingCar car; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
car = spy(new RacingCar(0)); | ||
} | ||
|
||
@Test | ||
void makeRandomNum() { | ||
int random = car.makeRandomNum(); | ||
assertTrue(random >= 0 && random <= 9); | ||
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. 이건 현재는 무조건 통과하는 테스트이고, 혹시 범위가 0~20 정도로 바뀌게 되면 이 테스트는 성공하기도, 실패하기도 하는 테스트라 검증을 못하고 넘어갈 수도 있어서 적절치 못한 테스트에요
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. 이건 현재는 무조건 통과하는 테스트이고, 혹시 범위가 0~20 정도로 바뀌게 되면 이 테스트는 성공하기도, 실패하기도 하는 테스트라 검증을 못하고 넘어갈 수도 있어서 적절치 못한 테스트에요
|
||
} | ||
|
||
@Test | ||
void progress() { | ||
// given | ||
doReturn(4).when(car).makeRandomNum(); | ||
int expected = car.getPos()+1; | ||
|
||
// when | ||
car.progress(); | ||
|
||
// then | ||
assertEquals(expected, car.getPos()); | ||
} | ||
} |
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.
while문을 쓸 필요가 있는걸까요 ?