자동차 경주 피드백

 

목적

이전 미션의 PR들을 보고 있다. 레벨 2가 끝나가는 시점에 잘 지켜지는 피드백도 있고, 그렇지 않은 피드백도 있다. 잘 이해가 되는 개념도 있고 그렇지 않은 개념도 있다. 그런 것들을 정리해 보려고 한다.

 

객체를 객체스럽게 사용해라

이번 지하철 미션에서도 한번 피드백을 받았다. 한번 더 리마인드 하면 좋을 것 같다.

        Line line = findById(id);
        Sections sections = line.getSections();
        List<Section> deleteSections = sections.deleteSection(stationId);
        Line line = findById(id);
        List<Section> deleteSections = line.deleteSection(stationId);

 

  • 객체는 캡슐화된 상태와 외부에 노출되어 있는 행동을 가지고 있다.
  • 이를 토대로 다른 객체와 메시지를 주고 받으면서 협력한다.
  • 객체는 메시지를 받으면 그에 따른 로직을 수행하게 되고, 이를 통해 객체 스스로 내부의 상태값을 변경한다.
  • getter로 데이터를 꺼내 로직을 처리하지 말고, 객체에 메시지를 보내 일을 하도록 리팩토링 한다.

https://woowacourse.github.io/javable/post/2020-04-28-ask-instead-of-getter/

 

getter를 사용하는 대신 객체에 메시지를 보내자

getter는 멤버변수의 값을 호출하는 메소드이고, setter는 멤버변수의 값을 변경시키는 메소드이다. 자바 빈 설계 규약에 따르면 자바 빈 클래스 설계 시, 클래스의 멤버변수의 접근제어자는 private

woowacourse.github.io

 

단위 테스트하기 어려운 코드를 단위 테스트하기

자동차 경주의 요구사항 중 아래와 같은 요구사항이 있다.

  • 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다.

일반적으로 테스트의 구조는 given/when/then 형식으로 짜여진다. 그러나 given을 통제할 수 없는 상황에서 어떻게 테스트를 해야하는지 많은 고민이 있었다. 이 부분은 자동차 경주 피드백의 PR 대부분에서 질문으로 들어가 있었다. 그래서 정리해보려고 한다.

전략패턴을 사용한다.

    @ParameterizedTest
    @DisplayName("랜덤 값이 4 이상일 경우 전진하고 3 이하의 값이면 멈춘다.")
    @CsvSource(value = {"1,1,1:0", "1,6,3:1", "6,5,7:3"}, delimiter = ':')
    public void move_랜덤_값이_4_이상일_경우_전진하고_3_이하의_값이면_멈춘다(String input, int expected) {
        int[] inputs = Arrays.stream(input.split(",")).mapToInt(Integer::parseInt).toArray();

        Car car = new Car("포비", new CarMoveCondition() {
            private int[] randomNumbers = inputs;
            private int index = 0;

            @Override
            public boolean isMovable() {
                return randomNumbers[index++] >= 4;
            }
        });

        for (int i = 0; i < inputs.length; i++) {
            car.move();
        }

        assertEquals(expected, car.getPosition());
    }

 

그때에는 움직임을 MoveCondition으로 추상해서 구현했었다. 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다. 라는 요구사항이 변하지 않는다면 move()에 파라미터로 값을 받는 것도 괜찮았을 것 같다.  파라미터를 추가하는 것 외에 상속을 사용한다. 라는 해결방법도 있는데 그것은 javable 포스팅에 자세히 나와 있다.

 

  • 파라미터를 추가한다.
  • 상속을 사용한다.

 

https://woowacourse.github.io/javable/post/2020-04-28-test-without-method-change/

 

메소드 시그니처를 변경하지 않고, 테스트 가능한 구조 만들기.

woowacourse.github.io

 

테스트 픽스처

'테스트만을 위해서 프로덕션 코드가 추가되는 것이 옳은가' 이게 부제목이 될 듯하다. 피드백에 테스트를 위한 편의 메서드를 구현코드에 구현하지 말라고 한다.  테스트 픽스처를 활용 해 보자.

 

테스트 픽스처

  • 테스트를 반복적으로 수행할 수 있게 도와주고 매번 동일한 결과를 얻을 수 있게 도와주는 기반이 되는 상태나 환경
  • 여러 테스트에서 공용으로 사용할 수 있는 테스트 픽스처는 테스트의 인스턴스 변수 혹은 별도의 클래스에 모아본다.

 

Car에 setPosition()을 만들지 말고, 테스트 클래스 내에 이 환경을 만들 수 있는 테스트 픽스처를 추가하자

    private Car createCar(String name, Integer position) {
        Car car = new Car(name);
        for (int i = 0; i < position; i++) {
            car.tryToMove(5);
        }
        return car;
    }

 

 

댓글



Designed by JB FACTORY