Random값은 어떻게 테스트 해야하나?

Hyunta·2022년 2월 21일
0

자동차 경주 미션

목록 보기
1/7

a. 테스트가 어렵거나 테스트할 수 없는 부분은 생길 수밖에 없다는 점을 먼저 말씀드릴게요. 이번의 경우에는 무작위로 숫자가 생성되는 부분이 그렇죠. 또 다른 예시로 시간을 들 수 있을텐데, LocalDateTime.now()의 반환값이 매번 다르다보니 테스트하기 어려운 경우에 속합니다.

b. 때문에 테스트가 가능한 부분은 테스트할 수 있도록 테스트하기 어려운 부분과 나누는 것이 중요한데요. 이번 미션을 예로 들면, "Random 클래스로 숫자를 생성하는 부분"은 테스트하기 어려운 부분에 속하지만 생성된 숫자에 따라 자동차가 기대한 대로 position을 바꾸는 부분은 비교적 테스트하기 쉬운 부분에 속합니다.

c. 지금은 두 부분이 Car 클래스에 함께 모여있다보니 테스트하기 쉬운 부분도 테스트가 어렵게 됐는데요. 두 부분을 어떻게 분리할 수 있을지 고민해보시면 좋겠습니다 😉

자동차를 랜덤값에 의해 움직이는 코드를 아래와 같이 구현했었다.

    public void move() {
        final int number = random.nextInt(RANDOM_NUMBER_UPPER_BOUND);

        if (number >= MOVABLE_LOWER_BOUND) {
            position++;
        }
    }

기능적으로는 문제가 생기지 않지만, 테스트를 하려니 막막해졌다. 매번 랜덤값에 의해 움직일지 말지 결정을 하다보니 자동차가 전진하는지를 확인하기가 어려웠다. 피드백을 통해 랜덤값을 만드는 기능과 움직이는 기능을 분리하기로 했다. 어떻게보면 현재 move()는 랜덤으로 값을 만들고 결과에 의해 움직일지 말지를 결정하므로 메서드가 두가지 기능을 하고 있다고 생각할 수 있다.

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

메서드 시그니처를 수정하여 랜덤값을 구하는 메서드를 따로 분리하고 나니 테스트하기 쉬워졌다. 해당 메서드는 입력하는 int 값에 의해 움직일지 말지를 결정하므로 테스트 코드는 아래와 같이 구현할 수 있다.

public class CarTest {

    @DisplayName("숫자가 4보다 작으면 위치를 그대로 유지")
    @Test
    public void move_NumberIsLessThanFour_KeepPosition() {
        // Given
        final Car car = new Car("test", 1);

        // When
        car.move(3);

        // Then
        assertThat(car).extracting("position").isEqualTo(1);
    }

    @DisplayName("숫자가 4보다 크거나 같으면 위치를 1 증가")
    @Test
    public void move_NumberIsEqualOrGreaterThanFour_IncreasePositionByOne() {
        // Given
        final Car car = new Car("test", 1);

        // When
        car.move(4);

        // Then
        assertThat(car).extracting("position").isEqualTo(2);
    }

}

이로써 move() 에 관한 테스트를 Random에 관계없이 수행할 수 있었습니다.

Reference:

https://tecoble.techcourse.co.kr/post/2020-05-07-appropriate_method_for_test_by_parameter/

profile
세상을 아름답게!

0개의 댓글