Skip to content

Latest commit

 

History

History
151 lines (117 loc) · 3.89 KB

테스트-가능한-코드-만들기.md

File metadata and controls

151 lines (117 loc) · 3.89 KB

테스트 가능한 코드 만들기

아래 코드는 오늘이 올해의 몇 번째 날인지 알려주는 코드입니다.

public class Sample {
    public static void main(String[] args) {
        DayCounter dayCounter = new DayCounter();
        int day = dayCounter.getDayOfYear();
        System.out.println(day);
    }
}

class DayCounter {
    public int getDayOfYear() {
        return LocalDate.now().getDayOfYear();
    }
}

목표는 돌려주는 값이 정확한지 알기 위해 getDayOfYear() 메서드를 테스트하는 것입니다.

getDayOfYear() 메서드는 LocalDate.now() 를 호출하고 있습니다.
LocalDate.now() 메서드는 호출할 때마다 다른 값을 반환하고, 이는 테스트를 어렵게 만듭니다.

class SampleTest {
    @Test
    void test() {
        LocalDate nowDate = LocalDate.now();

        assertThat(nowDate.getDayOfYear()).isEqualTo(??); // 오늘은 몇 번째 날?
    }
    
    @Test
    void test2() {
        Helper dayCounter = new Helper();

        int day = dayCounter.getDayOfYear();

        assertThat(day).isEqualTo(??); // 몇이 나와야 하지?
    }
}
  • 오늘은 호출 시점에 따라 1월 1일일수도, 12월 31일일수도 있습니다.

파라미터로 분리하기

테스트를 위해선 고정 값이 필요합니다. LocalDateTime을 파라미터로 받는 방법으로 해결을 시도해볼 수 있습니다.

class DayCounter {
    public int getDayOfYear(LocalDateTime targetDate) {
        return targetDate.getDayOfYear();
    }
}

class HelperTest {
    @Test
    void test() {
        LocalDate localDate = LocalDate.of(2023, 2, 1);
        DayCounter dayCounter = new DayCounter();

        int day = dayCounter.getDayOfYear(localDate);

        assertThat(day).isEqualTo(32); // 1월은 총 31일 + 2월 1일 -> 2월 1일은 1년 중 32
    }
}

해당 방법은 문제를 회피할 뿐, 해결해주지 않습니다.
예를 들어 DayCounter를 사용하는 Helper 클래스도 테스트가 불가능해지는 문제를 겪습니다.

public class Helper {
    public int help() {
        DayCounter dayCounter = new DayCounter();
        return dayCounter.getDayOfYear(LocalDate.now()); // LocalDate.now()를 의존
    }
}

class HelperTest {

    @Test
    void test() {
        Helper helper = new Helper();

        int day = helper.help();

        assertThat(day).isEqualTo(??); // 몇이 나와야 하지?
    }
}

생성자를 통해 주입받도록 변경하기

public class Helper {

    private final DateStrategy dateStrategy;

    public Helper(DateStrategy dateStrategy) {
        this.dateStrategy = dateStrategy;
    }

    public int help() {
        LocalDate targetDate = dateStrategy.getTargetDate();
        DayCounter dayCounter = new DayCounter();
        return dayCounter.getDayOfYear(targetDate);
    }

}

interface DateStrategy {
    LocalDate getTargetDate();
}

class DefaultDateStrategy implements DateStrategy {
    @Override
    public LocalDate getTargetDate() {
        return LocalDate.now();
    }
}

테스트용 Strategy를 만들어서 테스트를 진행합니다.

class TestDateStrategy implements DateStrategy {
    @Override
    public LocalDate getTargetDate() {
        return LocalDate.of(2023, 2, 1);
    }
}

class HelperTest {
    @Test
    void test() {
        // Helper helper = new Helper(() -> LocalDate.of(2023, 2, 1)); // 람다식으로도 표현 가능합니다.
        Helper helper = new Helper(new TestDateStrategy());

        int day = helper.help();

        assertThat(day).isEqualTo(32);
    }
}
  • 최종적으로 테스트가 가능해진 코드입니다.
  • getDayOfYear() 메서드 내에 계산식이 추가되거나 변경되어도 테스트가 가능합니다.

참고

읽어보면 좋은 글