아래 코드는 오늘이 올해의 몇 번째 날인지 알려주는 코드입니다.
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() 메서드 내에 계산식이 추가되거나 변경되어도 테스트가 가능합니다.
읽어보면 좋은 글
- jojoldu - 2. 테스트하기 좋은 코드 - 제어할 수 없는 코드 개선