우테코 5기/레벨1

전략 패턴을 통한 테스트

도둑탈을 쓴 애쉬 2023. 2. 17. 14:15
public void drive() {
				Random random = new Random();
        int number = random.nextInt(10);
        if (number >= 4) {
            position += 1;
        }
    }

자동차는 랜덤한 숫자를 하나 선택하고, 이가 4 이상이면 전진한다.

자동차의 전진 여부를 테스트하기 위해선 어떻게 해야할까?

@DisplayName("자동차 전진 테스트")
@Test
void driveTest() {
		Car car = new Car("test");
		car.drive();
		assertThat(car.getPosition()).isEqualTo(1);
}

이렇게 테스트하면.. 0~3이면 실패고, 4~9면 성공이니 60% 확률로 성공한다.

그러면 이를 @RepeatedTest(1000) 걸고 600번정도 성공하면 성공적으로 전진한것일까?

그렇게 불확실한 테스트를 과연 테스트라 부를 수 있을까?

그러면 이 친구를 테스트하기 위해선 어떻게 해야할까?

전략 패턴을 사용해 테스트하자

우선, NumberGenerator 인터페이스를 생성하고, 이를 상속받는 RandomNumberGenerator를 구현한다.

// NumberGenerator.java
public interface NumberGenerator {

    int generate();
}
// RandomNumberGenerator.java
public class RandomNumberGenerator implements NumberGenerator {

    private static final Random random = new Random();

    @Override
    public int generate() {
        return random.nextInt(10);
    }
}

다음으로 자동차 객채 생성시 RandomNumberGenerator를 주입해주고, 전진여부 판단 숫자를 고를 때 NumberGenerator를 사용한다.

// Car 객체 생성시 RandomNumberGenerator 주입
new Car("test", new RandomNumberGenerator());

// Car.java
public class Car {

    public Car(final String name, NumberGenerator numberGenerator) {
        this.name = name;
        this.numberGenerator = numberGenerator;
    }

    public void drive() {
        final int DRIVING_DISTANCE = 1;
        final int MOVING_STANDARD = 4;

        int number = numberGenerator.generate();
        if (number >= 4) {
            drivenDistance += 1;
        }
    }
}

이제 테스트를 위한 DrivableNumberGenerator과 NonDrivableNumberGenerator를 만들어주자!

이는 테스트를 위한 클래스들로, test 패키지 내에 위치시키자.

class DrivableNumberGenerator implements NumberGenerator {

    @Override
    public int generate() {
        return 4;
    }
}

class NonDrivableNumberGenerator implements NumberGenerator {

    @Override
    public int generate() {
        return 3;
    }
}

위 두 클래스를 이용해 테스트를 해주자!

@DisplayName("차량 전진 테스트")
@Test
void driveTest() {
    //given
    Car car = new Car("test", new DrivableNumberGenerator());
    //when
    car.drive();
    //then
    assertThat(car.getPosition()).isEqualTo(1);
    }

@DisplayName("차량 정지 테스트")
@Test
void nonDriveTest() {
    //given
    Car car = new Car("test", new NonDrivableNumberGenerator());
    //when
    car.drive();
    //then
    assertThat(car.getPosition()).isEqualTo(0);
}