공부/자바

[자바] 인터페이스를 분리하여(전략패턴) 테스트하기 좋은 메서드로 만들기

ghhong 2023. 2. 2. 17:41

출처: https://tecoble.techcourse.co.kr/post/2020-05-17-appropriate_method_for_test_by_interface/

 

인터페이스를 분리하여 테스트하기 좋은 메서드로 만들기

tecoble.techcourse.co.kr

 

인터페이스를 분리하여(전략패턴) 테스트하기 좋은 메서드로 만들기

전에 메서드 시그니처를 수정하여 테스트하기 좋은 메서드 만들기에서는 테스트하기 어려운 의존을 매개변수로 전달받아 테스트하였다. 방법은 의존 관계를 상위로 이동시키는 것에 불과하고, 응집도가 떨어지게 된다.

전략패턴을 활용하여 인터페이스 분리 테스트해보자.

public class Car {

private static final int MOVABLE_LOWER_BOUND = 4; //4 이상이면 이동 가능
   
private static final int RANDOM_NUMBER_UPPER_BOUND = 10; //0~9 사이의 랜덤 값을 위한 상수

private final String name;
   
private int position;

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

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

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

}

 

 

기존에는 코드에서 move 메서드에 매개변수를 전달하여(메서드 시그니처를 수정하여) 테스트를 진행했다. 하지만 방법은 그저 의존관계를 상위로 이동시킨 뿐이다.

운영환경에서는 move 랜덤한 값을 갖게 하고, 테스트환경에서는 의도한 (MOVABLE_LOWER_BOUND 기준) 받도록 하면 된다.

이를 가능하게 하기 위해 인터페이스 분리를 수행한다.

전략패턴을 이용해보자.

move메서드에 number 매개변수로 받아서 메서드 내에서 사용한다면, 매개변수로 int 반환할 있는 인터페이스를 받도록 하여 사용해보자.

인터페이스 :

public interface NumberGenerator {

int generate();

}


NumberGenerator 인터페이스의 generate 메서드에서 int타입의 값을 반환하는 인터페이스다. 인터페이스를 활용하여 move메서드를 수정하면 다음과 같다.

public void move(NumberGenerator numberGenerator) {
   
final int number = numberGenerator.generate();

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

}

move메서드는 NumberGenerator 구현한 하위 클래스를 받기만 하면 된다. 내부에서 인터페이스가 갖고있는 generate메서드를 사용하여(어떻게 구현되어있는지 관심이 없다.) int 반환한다.

랜덤값을 반환하는 클래스와 특정 값을 반환하는 클래스를 만들면 다음과 같다.

public class RandomNumberGenerator implements NumberGenerator {

private static final int RANDOM_NUMBER_UPPER_BOUND = 10;

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

}

NumberGenerator generate메서드를 오버라이드하여 랜덤값을 반환한다.

 

운영코드에서는 다음과 같이 사용한다.

public void moveCarByRandomNumber() {
   
// name: 스티치, position: 1 인 Car 객체 생성
   
final Car car = new Car("스티치", 1);
   
// 랜덤한 숫자를 생성하는 RandomNumberGenerator 객체 생성
   
final NumberGenerator numberGenerator = new RandomNumberGenerator();

car.move(numberGenerator);
}

 

이번엔 특정 값을 반환하는 클래스를 만들자.

public class MovableNumberGenerator implements NumberGenerator {

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

}

특정값인 4 반환하여 Car 이동하기를 기대하는 메서드를 만들었다.

테스트코드 :

public class CarTest {

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

// When
        car
.move(numberGenerator);

// Then
       
assertThat(car).extracting("position").isEqualTo(2);// 위치가 1 증가하여 2 것이라 기대
   
}

}

 

마무리

인터페이스 분리를 사용하여 응집도가 높은 테스트 코드를 작성할 있다.