Junit 랜덤값을 테스트 하는 법

반달·2023년 2월 20일
0

우테코 코드리뷰

목록 보기
3/3

들어가기전에

  • 자동차 경주 미션
    - 0 ~ 9 까지 랜덤으로 하나를 뽑아 4이상이면 전진하는 조건
  • 랜덤의 요소 때문에 테스트하기가 어려웠다.

문제코드

    fun moveCars() {
        _cars.forEach { car: Car -> car.move(createRandomNumber()) }
    }

리뷰어님: RacingGame을 random의 요소 때문에 온전히 테스트하고 있지 못하고 있어요.
랜덤의 요소를 바깥에서 받아오게끔 바꾼 뒤, move등을 할 때 원하는 자동차가 원하는 거리를 움직 였는 지 등의 테스트를 작성해보아요 :)

리뷰어님 : 랜덤의 요소를 메서드 혹은 생성자를 통해 받음으로써 랜덤에 대해 독립시켜보는 것은 어떨까요?


당시의 나: 무슨말인지 모르겠어요 😱

랜덤을 테스트 한다? 처음 배우는 입장에서 조금 난해 했다.
어떻게 해야하지? 수도없이 많은 테스트를 돌려야하나?
조금만 생각하면 되는것이었다.
랜덤을 제어하는 방법이 필요한 것이었다.
이제야 알았다.... 인터페이스로 왜 랜덤을 관리하는지...

일단 다음은 내 개선된 코드이다.

fun moveCars(cars: List<Car>, randomNumberGenerator: NumberGenerator): List<Car> {
        cars.forEach { car: Car -> car.move(randomNumberGenerator.generate()) }
        return cars
    }

보면 인자로 NumberGenerator를 받고 있는데 이것을 테스트 할 때 따로 구현을 해 랜덤을 제어할 수가 있는 것이다.

// 프로덕션 코드
class RandomNumberGenerator : NumberGenerator {
    override fun generate(): Int {
        val range = MIN_RANGE..MAX_RANGE
        return range.random()
    }

    companion object {
        const val MIN_RANGE = 0
        const val MAX_RANGE = 9
    }
}
// 테스트용 코드
    inner class OneMoveRandomNumbers : NumberGenerator {

        private val pattern = listOf(PROGRESS, STOP, STOP)
        private var i = 0

        override fun generate(): Int {
            return pattern[i++]
        }
    }

위의 moveCars를 테스트 하려면 랜덤을 제어 할 수 있어야 한다. 그러기 위해서 랜덤으로 나올 수 있는 값을 제어하도록 한 것이다.
위의 경우엔 전진, 정지, 정지를 리턴하도록 강제한 것이다.
이렇게 만들어 놓으면 같은 NumberGenerator를 상속받아 만든 것이기 때문에 moveCars()에 인자로 들어갈 수 있게 된다. 그러므로 테스트가 가능한 것이다.


테스트 코드 리팩토링 하기

랜덤 값을 제어하기 위해 inner class를 구현하는 불편함이 있었다.
이를 편하게 사용 할수 있는 방법을 리뷰어님이 알려주셨다.

fun interface NumberGenerator {
    fun generate(): Int
}

리뷰어님 : NumberGenerator를 fun interface로 선언하면, 해당 인터페이스를 마지막 파라미터로 넘길 때 람다로 넘길 수 있게 됩니다.
즉, inner class 등으로 구현체를 직접 만들지 않아도 됩니다 :)
SAM에 대해 공부해보시길 추천드릴게요 😊

//수정 전
val movedCars: List<Car> = RacingGame.moveCars(cars, OneMoveRandomNumbers())

//수정 후 
val movedCars: List<Car> = RacingGame.moveCars(cars) { 1 }
profile
깊이 있는 안드로이드 개발자가 되기 위해

0개의 댓글