Skip to content
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

Step3 자동차경주 #5516

Open
wants to merge 9 commits into
base: kimsangha617
Choose a base branch
from
Open
21 changes: 21 additions & 0 deletions src/main/java/study/racingcar/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package study.racingcar;

import java.util.Random;

public class Car {

boolean move;
kimsangha617 marked this conversation as resolved.
Show resolved Hide resolved
public Car() {

}
kimsangha617 marked this conversation as resolved.
Show resolved Hide resolved

public boolean canMove() {
Random random = new Random();

return random.nextInt(10) >= 4;
}

public void move() {
System.out.print("-");
}
Copy link
Member

Choose a reason for hiding this comment

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

자동차는 움직일 수 있어야 하지만 특정 조건인 경우에만 움직일 수 있는데요
canMove를 누가 호출해 주지 않으면 조건에 부합하는지 알 수 있는 방법이 없습니다
자동차 객체가 스스로의 움직임을 제어할 수 있도록 move 메서드 내부에서 canMove 메서드를 호출하면 어떨까요?
외부에서는 move 메서드만 호출하게 하고 움직일지 말지는 자동차가 직접 결정하는거죠

Copy link
Member

Choose a reason for hiding this comment

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

자동차가 움직일 경우 바로 출력을 해버리면 현재 몇 칸을 전진했는지 알 수 있는 방법이 없는데요
move 메서드 내부에서 System.out.println으로 출력하기 보다 위치 값을 증가 시키면 어떨까요?
Car 내부에 private int position; 변수가 있다면 자동차가 전진한 위치값을 가질 수 있겠네요
추가로 테스트까지 할 수 있을 것 같습니다. 지금 테스트 코드가 하나도 없으니 move 메서드에 대한 테스트를 작성해 보시면 좋을 것 같아요

Copy link
Author

Choose a reason for hiding this comment

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

위치값을 증가시키고 몇 칸을 전진 했는지 알려면 스레드를 돌려야 할까요 ?
for문을 돌려 "-" 을 찍어주는 형태로 구현해봤는데요...

그리고 move 메소드를 테스트 할 때 canMove() 를 호출해야 하는데 canMove()는 Random 값이 4이상이었을 때만 테스트가 가능해보이는데.. 일정한 값이 나오는 테스트를 구현할 수 있을까요 ?

Copy link
Member

Choose a reason for hiding this comment

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

미션의 핵심을 잘 짚어주셨습니다 👍

위치값을 증가시키고 몇 칸을 전진 했는지 알려면 스레드를 돌려야 할까요 ?
for문을 돌려 "-" 을 찍어주는 형태로 구현해봤는데요...

과정내의 모든 미션에서 스레드를 직접 제어하실 필요는 없습니다.
자동차의 위치를 알 수 있는 방법은 여러가지가 있을 수 있는데요
아주 간단한 방법으로는 이동을 시도할 때마다 위치 값으로 출력을 해주시면 됩니다

for (Car car : List<Car> cars) {
    car.move();
    System.out.println(car.getPosition());
}

그리고 move 메소드를 테스트 할 때 canMove() 를 호출해야 하는데 canMove()는 Random 값이 4이상이었을 때만 테스트가 가능해보이는데.. 일정한 값이 나오는 테스트를 구현할 수 있을까요 ?

이 부분이 미션의 핵심인데요
canMove 메서드 내부에 Random으로 인해 테스트가 어려운 구조로 되어 있습니다
요구사항 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4이상일 경우이다. 는 조금 더 작은 단위로 나눠볼 수 있습니다

  1. 자동차는 4이상인 경우 전진한다
  2. 숫자는 랜덤으로 구한다
    위와 같이 2개의 기능으로 나눈다면 자동차는 직접 랜덤으로 숫자를 구할 필요가 없게 됩니다
    자동차는 전진하는 조건에 부합하기만 하면 전진하면 됩니다
    랜덤으로 구해진 숫자는 외부에서 전달해주면 됩니다
public void move(int number) {
    if (canMove(number)) {
        이동();
    }
}

테스트하고자 하는 내용이 '자동차의 전진'인지 '랜덤 값 구하기'인지 고민해 보시면 좋을 것 같아요
혹시 2차 라이브 강의를 아직 보지 않으셨다면 꼭 보시고 진행하시길 추천드립니다

Copy link
Author

Choose a reason for hiding this comment

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

네 답변 감사합니다 용주님 slack 으로 dm 4일전에 보냈는데 확인을 안해주신것 같아요 ㅠ 확인 한 번 부탁드립니다
2차 라이브 강의 보면서 더 진행해보겠습니다

그리고 어제 깃 푸시 했는데 푸시한 코드가 반영이 안됐을까요 ? 안보이네요..

}
34 changes: 34 additions & 0 deletions src/main/java/study/racingcar/RacingCar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package study.racingcar;

import java.util.Random;
import java.util.Scanner;

public class RacingCar{



public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

System.out.println("자동차 대수는 몇 대 인가요?");
int givenCars = scanner.nextInt();
System.out.println("시도할 회수는 몇 회 인가요?");
int triedCount = scanner.nextInt();

Car[] cars = new Car[givenCars];
Copy link
Member

Choose a reason for hiding this comment

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

배열은 공변 문제로 인해 사용을 권장드리지 않습니다 List 인터페이스를 활용해 주세요


for (int i = 0; i < givenCars; i++) {
cars[i] = new Car();

for (int j = 0; j < triedCount; j++) {
if (cars[i].canMove()) {
cars[i].move();
}
}
System.out.println();
}
}


}
6 changes: 6 additions & 0 deletions src/main/java/study/racingcar/dto/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package study.racingcar.dto;

public class InputView {
Copy link
Member

Choose a reason for hiding this comment

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

inputview가 dto 패키지에 위치하는 것은 적절하지 않은 것 같아요
view 라는 패키지로 이동하면 어떨까요?



}
4 changes: 4 additions & 0 deletions src/main/java/study/racingcar/dto/ResultView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package study.racingcar.dto;

public class ResultView {
}
69 changes: 69 additions & 0 deletions src/main/java/study/step02/StringPlusCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package study.step02;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* 객체지향 생활 체조원칙
* 게터세터 사용 x
* 한 메서드에 오직 한 단계의 들여쓰기만
* else 예약어 사용 x
*/

public class StringPlusCalculator {

private static final String DEFAULT_DELIMITER = "[,:]";
private static final String CUSTOM_DELIMITER = "//(.)\n(.*)";

private static int result;

public static int splitAndSum(String givenString) {
if (givenString == null || givenString.isEmpty()) {
return 0;
}
String[] stringTokens = splitWithDelimiter(givenString);
int[] intTokens = stringTokensToInt(stringTokens);
if (!verifyPositiveNumber(intTokens)) {
throw new RuntimeException();
}

return sumAll(intTokens);
}

private static String[] splitWithDelimiter(String givenString) {

Pattern pattern = Pattern.compile(CUSTOM_DELIMITER);
Matcher matcher = pattern.matcher(givenString);
if (matcher.find()) {
String findDelimiter = matcher.group(1);
String stringToken = matcher.group(2);
return stringToken.split(findDelimiter);
}
return givenString.split(DEFAULT_DELIMITER);
}

private static int[] stringTokensToInt(String[] stringTokens) {
int[] numbers = new int[stringTokens.length];
for (int i = 0; i < stringTokens.length; i++) {
numbers[i] = Integer.parseInt(stringTokens[i]);
}
return numbers;
}
private static boolean verifyPositiveNumber(int[] intTokens) {
for (int token: intTokens) {
if (token < 0) {
return false;
}
}
return true;
}

private static int sumAll(int[] numbers) {
int sum = 0;
for(int number: numbers) {
sum += number;
}
return sum;
}

}
70 changes: 70 additions & 0 deletions src/test/java/study/step01/SetCollectionPlaygroundTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package study.step01;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("step01 - Set Collection에 대한 학습테스트")
public class SetCollectionPlaygroundTest {

private Set<Integer> numbers;

@BeforeEach
void setUp() {
numbers = new HashSet<>();
numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);
}

@DisplayName("요구사항1 - size() 메소드를 활용 Set 크기 테스트")
@Test
public void setSize_TestSetSize() {
// assertThat(numbers.size()).isEqualTo(3);
assertThat(numbers).hasSize(3);
}

private static Stream<Arguments> paramsForContainsTest() {
return Stream.of(
Arguments.of(1),
Arguments.of(2),
Arguments.of(3)
);
}

@DisplayName("요구사항2 - contains() 메소드를 활용 1,2,3 값 존재 확인 테스트, ParameterizedTest - MethodSource 활용")
@ParameterizedTest
@MethodSource("paramsForContainsTest")
public void setContains_TestWithMethodSource(int value) {
assertThat(numbers).contains(value);
}

@DisplayName("요구사항2 - contains() 메소드를 활용 1,2,3 값 존재 확인 테스트, ParameterizedTest - ValueSource 활용")
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
public void setContains_TestWithValueSource(int value) {
assertThat(numbers).contains(value);
}

@DisplayName("요구사항3 - contains() 메소드를 활용하여 입력값에 따라 결과값이 다른 경우 테스트")
@ParameterizedTest
@CsvSource(value = {"1,true", "2,true", "3,true", "4,false", "5,false"}) // default delimiter is comma(,)
public void setContains_ReturnTrueIfValueIsPresentInNumbers(int value, boolean expected) {
assertEquals(expected, numbers.contains(value));
}


}
48 changes: 48 additions & 0 deletions src/test/java/study/step01/StringPlaygroundTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package study.step01;

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.Assertions.assertThatThrownBy;

@DisplayName("step01 - String 클래스에 대한 학습테스트")
public class StringPlaygroundTest {

@DisplayName("요구사항1 - split 테스트")
@Test
public void splitString_toArray() {
String givenString = "1,2";
String[] result = givenString.split(",");
// assertThat(result).hasSize(2);
// assertThat(result).contains("1");
// assertThat(result).contains("2");
assertThat(result).containsExactly("1", "2"); // containsExactly is same as hasSize() and contains()
}

@DisplayName("요구사항2 - substring 테스트")
@Test
public void substring_getString() {
String givenString = "(1,2)";
String result = givenString.substring(1, 4);
assertThat(result).isEqualTo("1,2");
}

@DisplayName("요구사항3 - charAt()을 이용한 특정위치의 문자를 가져온다")
@Test
public void charAt_getChar() {
String givenString = "abc";
char result = givenString.charAt(1);
assertThat(result).isEqualTo('b');

}

@DisplayName("요구사항4 - 특정위치의 문자를 가져올 때 범위를 벗어나면 exception")
@Test
public void charAtFail_outOfRange() {
String givenString = "abc";
assertThatThrownBy( () -> givenString.charAt(3)).isInstanceOf(StringIndexOutOfBoundsException.class)
.hasMessageContaining("index out of range: 3");

}
}
65 changes: 65 additions & 0 deletions src/test/java/study/step02/StringPlusCalculatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package study.step02;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 (예: “” => 0, "1,2" => 3, "1,2,3" => 6, “1,2:3” => 6)
* 앞의 기본 구분자(쉼표, 콜론)외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 “//”와 “\n” 사이에 위치하는 문자를 커스텀 구분자로 사용한다. 예를 들어 “//;\n1;2;3”과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
* 문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우 RuntimeException 예외를 throw한다.
*
* ** 요구사항 **
* 메소드가 너무 많은 일을 하지 않도록 분리하기 위해 노력해 본다.
*/
public class StringPlusCalculatorTest {

@Test
void givenStringNullThenReturnZero() {
String givenString = null;
int result = StringPlusCalculator.splitAndSum(givenString);
assertThat(result).isEqualTo(0);
}

@Test
void givenStringEmptyThenReturnZero() {
String givenString = "";
int result = StringPlusCalculator.splitAndSum(givenString);
assertThat(result).isEqualTo(0);
}

@Test
void givenOneStringWithCommaDelimiterAddTest() {
int result = StringPlusCalculator.splitAndSum("1");
assertThat(result).isEqualTo(1);
}

@Test
void givenStringWithCommaDelimiterAddTest() {
int result = StringPlusCalculator.splitAndSum("1,2,3");
assertThat(result).isEqualTo(6);
}

@Test
void givenStringWithMixedDelimiterAddTest() {
int result = StringPlusCalculator.splitAndSum("1,2:3");
assertThat(result).isEqualTo(6);
}

@Test
void givenStringWithCustomDelimiterAddTest() {
int result = StringPlusCalculator.splitAndSum("//;\n1;2;3");
assertThat(result).isEqualTo(6);
}

@Test
public void givenStringWithNegativeNumberReturnRuntimeException() throws Exception {
assertThatThrownBy(() -> StringPlusCalculator.splitAndSum("-1,2,3"))
.isInstanceOf(RuntimeException.class);
}
}