테스트 코드를 작성하다보면 문득 private 메서드와 관련된 테스트는 어떻게 작성해야할까 하고 고민을 하는 시점이 있다.
Private 메서드와 관련된 테스트 코드는 개인적으로 작성하지 않고 있는데 해당 이유에 대해서 생각보다 스스로 명쾌히 대답하지 못한다는 느낌을 받았다.
즉, Private 메서드의 테스트 코드는 지양해야한다고 알고있지만, 그 이유는 무엇이고 그럼에도 불구하고 긴급하게 작성해야한다면 어떤 식으로 작성할 수 있을지를 알아봤다.
package io.springbatch.privatetest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.springframework.boot.test.context.SpringBootTest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class PrivateTestClassTest {
@InjectMocks
private PrivateTestClass target;
@DisplayName("")
@Test
void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//given
String name = "Hello";
Method method = target.getClass().getDeclaredMethod("isPredefiened", String.class);
method.setAccessible(true);
//when
boolean result =(boolean) method.invoke(target, name);
//then
Assertions.assertThat(result).isEqualTo(true);
}
}
@SpringBootTest
class PrivateTestClassTest {
@InjectMocks
private PrivateTestClass target;
@DisplayName("")
@Test
void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//given
String name = "Hello";
Method method = target.getClass().getDeclaredMethod("isPredefiened", String.class);
method.setAccessible(true);
ReflectionUtils.invokeMethod(method, target);
//when
boolean result =(boolean) method.invoke(target, name);
//then
Assertions.assertThat(result).isEqualTo(true);
}
}
따라서 가장 권장되는 방식은, private 메서드를 직접 테스트하기 보다는 접근제어자가 public인 메서드를 가장 우선적으로 테스트하되 성공하는 테스트 케이스와 실패하는 테스트 케이스를 나눠서 private 메서드를 커버해야한다.
가령, @ParameterizedTest를 이용하게 되면 동일한 테스트를 여러 개의 파라미터로 실행 가능하다.
[JUnit5] @ParameterizedTest로 한 번에 테스트하자
그럼에도 분리하고 private 메서드 자체를 직접 테스트해야하는 상황이라면 해당 메서드의 기능이 너무 커진 것 아닌가? 혹은 클래스를 분리해야하는가를 고민해야하는 시점이라고 할 수 있겠다.
즉 동일한 클래스에서 public 메서드에서 private 메서드를 호출하는 것이 아닌, 해당 private 메서드를 새로운 클래스를 작성하여 의존관계를 주입하여 작성하는 것이 객체지향의 관점에서는 더 올바르다고 할 수 있겠다.