본문 바로가기

etc/우테코 6기 프리코스

2주차 프리코스 미션(자동차 경주)

기능 요구 사항 & 프로그램 요구 사항 & 과제 진행 요구 사항


GitHub : https://github.com/JunTaeINC/java-racingcar-6

 

GitHub - JunTaeINC/java-racingcar-6: 우아한 테크코스 6기 프리코스 2주차

우아한 테크코스 6기 프리코스 2주차. Contribute to JunTaeINC/java-racingcar-6 development by creating an account on GitHub.

github.com

 

 

 

문제 해결


1. 객체 지향적 설계

처음에 어떤 객체를 생성해야 할지 고민을 많이 했다. 게임의 주체인 '자동차'는 당연히 객체로 만들어야 했다. 하지만 경기 진행에 관련된 기능을 어떻게 처리할지 고민이 되었다. 1주 차에는 GameManager 클래스를 생성을 했었는데 이번에는 Race라는 경기 진행을 도와주는 객체를 만들어 그 안에 게임 진행에 관련된 기능을 처리하도록 했다. 이렇게 객체를 나누고 각 객체에 적절한 역할을 부여함으로써, 코드의 구조가 더욱 명확해졌고, 각 객체의 역할이 뚜렷해져 가독성이 좋아졌다.

 

1.1 Car Class

package racingcar.domain;

public class Car {

	private static final int MOVE_CONDITION = 4;

	private final String name;
	private int position;

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

	public void move(int number) {
		if (number >= MOVE_CONDITION) {
			position++;
		}
	}

	public String getName() {
		return name;
	}

	public int getPosition() {
		return position;
	}
}

 

1.2 Race Class

package racingcar.domain;

import java.util.ArrayList;
import java.util.List;
import racingcar.util.RandomUtil;
import racingcar.validators.InvalidInputValidators;

public class Race {

	private final List<Car> cars = new ArrayList<>();
	private final InvalidInputValidators invalidInputValidators = new InvalidInputValidators();

	public Race(String[] carNames) {
		for (String name : carNames) {
			invalidInputValidators.validateCarName(name);
			cars.add(new Car(name));
		}
	}

	public void run() {
		for (Car car : cars) {
			int randomNumber = RandomUtil.getRandomNumber();
			car.move(randomNumber);
		}
	}

	public int getMaxRecord() {
		int max = 0;
		for (Car car : cars) {
			max = Math.max(car.getPosition(), max);
		}

		return max;
	}

	public List<Car> getCars() {
		return cars;
	}
}

 

 

2. 출력 관련 테스트 코드

이전 1주 차에 Mockitospy() 메서드를 활용해서 테스트를 구현했지만, 이번에는 출력에 내용을 테스트하는 코드가 필요했다. 자바 표준 라이브러리인 ByteArrayOutputStream를 사용해 출력메시지에 관한 테스트 코드를 작성했다.

 

2.1 테스트 환경 설정

출력메서드(System.out) 출력 내용을 ByteArrayOutputStream객체에 저장

@BeforeEach
public void setUpStreams() {
	System.setOut(new PrintStream(outputResult));
	resultView = new ResultView();

	String[] carNames = {"car1", "car2", "car3"};
	race = new Race(carNames);
	// car1
	race.getCars().get(0).move(8);
	race.getCars().get(0).move(7);
	// car2
	race.getCars().get(1).move(6);
	// car3
	race.getCars().get(2).move(1);
}
@AfterEach
public void restoreStreams() {
	System.setOut(System.out);
}

 

2.2 검증

@Test
public void getResult() {
	resultView.getResult(race);
	String expectedOutput = "car1 : --\n" +
		"car2 : -\n" +
		"car3 : \n";

	assertThat(expectedOutput.trim()).isEqualTo(outputResult.toString().trim());
}

@Test
public void getFinalWinner() {
	resultView.getFinalWinner(race);
	String expectedOutput = "최종 우승자 : car1";

	assertThat(expectedOutput).isEqualTo(outputResult.toString());
}

 

 

 

미션 진행 후기


OOP를 지키려고 많이 고민을 했었다. 또한 한 가지의 책임을 갖게 함으로써 메서드가 정확한 기능을 하고 메서드명을 분명하게 지음으로써 가독성 향상을 느낄 수 있었다. 어떻게 객체를 나눠야 하는지 배우게 된 시간이었다. 

아직까지 테스트 코드작성이 어려워 조금 부자연스럽지만 테스트 코드의 중요성을 알기 때문에 꾸준하게 테스트 코드 작성도 게을리하지 말아야 한다고 생각한다. 아마 3주 차부터는 제한사항이 더 많아지며 interface 클래스를 활용하는 문제가 나올 것 같다. 5기에는 진행되었다.