Study/우아한 테크 코스 / / 2023. 11. 6. 22:34

테스트는 왜 해야할까? 내가 생각하는 테스트코드를 작성하는 이유

테스트와 OCP의 관계

테스트를 작성하는 여러 이유 중 하나는 객체 지향 설계 원칙 중 OCP(Open-Closed Principle)와 관련이 있다. 이 원칙은 클래스는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다는 것을 의미한다. 이 원칙을 지키지 않을 경우, 테스트하기 어려운 코드가 발생할 수 있다. 예를 들어, 랜덤한 숫자를 가져와야 하는 로직이 있다면, 이 로직을 테스트하는 것이 어려울 수 있다.


랜덤넘버를 이용한 코드와 테스트

[문제 상황]
랜덤한 숫자를 이용해서 게임을 진행하는 코드가 있다고 가정하자. 이러한 로직은 직접 테스트하기 어렵다.

public class RandomGame {
    public String play() {
        int randomNumber = (int) (Math.random() * 10);
        if(randomNumber > 5) {
            return "Win!";
        } else {
            return "Lose!";
        }
    }
}

위의 코드는 랜덤한 숫자에 따라 결과가 달라지기 때문에 예측 가능한 테스트를 작성하기 어렵다.

OCP를 적용한 해결 방안

OCP를 이용해서 문제를 해결하려면 랜덤 로직을 외부에서 주입받을 수 있도록 변경해야 한다. 이렇게 하면 테스트할 때는 랜덤 대신 예측 가능한 값을 사용할 수 있다.

[테스트하기 편한 예측 가능한 클래스]

public class RandomGame {
    private final RandomNumberProvider randomNumberProvider;

    public RandomGame(RandomNumberProvider randomNumberProvider) {
        this.randomNumberProvider = randomNumberProvider;
    }

    public String play() {
        int randomNumber = randomNumberProvider.getRandomNumber();
        if(randomNumber > 5) {
            return "Win!";
        } else {
            return "Lose!";
        }
    }
}

interface RandomNumberProvider {
    int getRandomNumber();
}

 

[테스트 코드를 위한 구현] - 일반적으로는 테스트를 위해 클래스를 작성하면 안된다! (익명클래스 참고)

public class TestRandomNumberProvider implements RandomNumberProvider {
    private final int number;

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

    @Override
    public int getRandomNumber() {
        return number;
    }
}

 

[테스트 코드]

public class RandomGameTest {

    @Test
    public void givenNumberGreaterThan5_whenPlay_thenWin() {
        RandomGame game = new RandomGame(new TestRandomNumberProvider(6));
        assertThat(game.play()).isEqualTo("Win!");
    }

    @Test
    public void givenNumberLessThan5_whenPlay_thenLose() {
        RandomGame game = new RandomGame(new TestRandomNumberProvider(4));
        assertThat(game.play()).isEqualTo("Lose!");
    }
}

이와 같이 OCP를 적용하면 랜덤 로직을 Mocking하거나 대체 구현을 통해 예측 가능한 값을 사용하여 테스트할 수 있다. 이렇게 단위 테스트를 통해 빠른 피드백을 받고, 해당 클래스의 실패원자성을 보장할 수 있다.

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유