[Java] 테스트와 인터페이스

Sony·2020년 4월 17일
2

자바(Java)

목록 보기
2/3

테스트하기 어려운 코드가 생기면 인터페이스 추출을 생각하자!

테스트하기 어려운 코드를 테스트 가능한 구조로 변경하기

다음 Car 객체의 move() 메소드의 이동/정지를 테스트하고 싶은데 테스트하기 힘들다. move() 메소드 내에 random 값이 생성되고 있기 때문이다. move() 메소드를 테스트 하기 위해선 어떻게 해야할까? 단, random 값을 메소드의 인자로 전달해 해결하면 안 된다.

힌트: 인터페이스를 활용한다.

public class Car {
    private static final int FORWARD_NUM = 4;
    private static final int MAX_BOUND = 10;

    private int position = 0;

    public void move() {
        if (getRandomNo() >= FORWARD_NUM)
            this.position++;
    }

    private int getRandomNo() {
        Random random = new Random();
        return random.nextInt(MAX_BOUND);
    }
}

의존성 주입(Dependency Injection)을 활용해 해결한다.

MoveStrategy: Car에서 도출 —> 인터페이스

RandomMoveStrategy: 클라이언트 요구에 의한 도출 —> MoveStrategy를 구현한 클래스

public class Car {
    private int position;

    public Car() {
        this.position = 0;
    }

    public void move(MoveStrategy moveStrategy) {
        if (moveStrategy.isMovable()) {
            this.position++;
        }
    }

    public int getPosition() {
        return position;
    }
}
public interface MoveStrategy {
    boolean isMovable()    
}
import java.util.Random;

public class RandomMoveStrategy implements MoveStrategy {
    private static final int FORWARD_NUM = 4;
    private static final int MAX_BOUND = 10;

    @Override
    public boolean isMovable() {
        return generateRandomNumber() >= FORWARD_NUM;
    }

    private int generateRandomNumber() {
        Random random = new Random();
        return random.nextInt(MAX_BOUND);
    }
}

Car.move()를 테스트 할 때는 테스트 내에서 특정 숫자를 반환하는 MoveStrategy 객체를 구현 한 후 Car.move()의 인자로 주입해주면 된다.

테스트 코드

class CarTest {
    public static final int MOVE_FORWARD_NUM = 4;
    public static final int STAY_NUM = 3;

    private Car car;

    @BeforeEach
    void setUp() {
        car = new Car();
    }

    @Test
    @DisplayName("5이상이면 전진한다")
    void move_forward() {
        car.move(new TestMoveStrategy(MOVE_FORWARD_NUM));
        assertThat(car.getPosition()).isEqualTo(1);
    }

    @Test
    @DisplayName("5 미만이면 전진하지 않는다.")
    void stay() {
        car.move(new TestMoveStrategy(STAY_NUM));
        assertThat(car.getPosition()).isEqualTo(0);
    }
}
class TestMoveStrategy implements MoveStrategy {
    private static final int FORWARD_NUM = 4;
    private final int number;

    public TestMoveStrategy(int number) {
        this.number = number;
    }

    @Override
    public boolean isMovable() {
        return number >= FORWARD_NUM;
    }
}

TestMoveStrategy를 따로 만들지 않고 람다식을 이용해 테스트해도 된다.

class CarTest {
    private Car car;

    @BeforeEach
    void setUp() {
        car = new Car();
    }

    @Test
    @DisplayName("전진한다")
    void move_forward() {
        car.move(() -> true);
        assertThat(car.getPosition()).isEqualTo(1);
    }

    @Test
    @DisplayName("전진하지 않는다.")
    void stay() {
        car.move(() -> false);
        assertThat(car.getPosition()).isEqualTo(0);
    }
}

Reference

profile
개발하며 배운점과 회고를 남기는 공간입니다.

0개의 댓글