JUnit private method test

지금껏 테스트 케이스를 작성할 때 public 메소드를 통하여 private 메소드를 테스트 하곤 했는데 private 메소드를 테스트 할 일이 생겨 reflection을 이용하여 유틸 클래스를 작성하게 되었다.


private 접근 제어자가 필드 및 메소드에 존재할지라도 외부 클래스에서 setAccessible(true)로 지정하면 접근이 가능하다.


한 가지 아쉬운 점은 reflection을 이용하여 메소드 테스트를 하고 싶을 때 메소드 이름을 문자열로 넘겨야 한다는 것이다. 이와 같이 메소드 이름을 하드 코딩으로 넘기게 되면 리펙토링에 취약하다는 단점이 있다. (private method 이름을 바꿔버리면? 테스트 실패)


powermock 라이브러리도 private method를  테스트 할 때 메소드 이름을 넘기는 식으로 되어 있던데 안 넘기고 테스트를 할 수 있는 방법이 어디 없을까?


package reflection.test_case;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
/**
* @FileName : ReflectionUtils.java
* @Project : test_project
* @작성자 : nklee
* @프로그램설명 :
*/
public class ReflectionUtils {
/**
* <pre>
* invokeMethod
* private method 테스트를 위한 util
* <pre>
* @param obj
* @param methodName
* @param returnType
* @param args
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T invokeMethod(Class<?> clazz, String methodName, Class<T> returnType, Object... args) {
Class<?>[] parameters = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
parameters[i] = args[i].getClass();
}
try {
Object obj = clazz.newInstance();
Method method = obj.getClass().getDeclaredMethod(methodName, parameters);
method.setAccessible(true);
return (T) method.invoke(obj, args);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@Test
public void accessPrivateMethodTest1() {
assertThat("namkyu", is(ReflectionUtils.invokeMethod(UserService.class, "getUser", String.class, "namkyu")));
}
@Test
@SuppressWarnings("unchecked")
public void accessPrivateMethodTest2() {
List<String> list = ReflectionUtils.invokeMethod(UserService.class, "getUsers", List.class, "namkyu");
assertThat("kyu", is(list.get(0)));
assertThat("kyu2", is(list.get(1)));
}
}
class UserService {
public String getUser(String userName) {
return makeUser(userName);
}
private String makeUser(String userName) {
return userName;
}
public List<String> getUsers(String userName) {
return makeUserList();
}
private List<String> makeUserList() {
List<String> list = new ArrayList<String>();
list.add("kyu");
list.add("kyu2");
return list;
}
}