Private 메소드를 테스트하고 싶다고?

이호석·2023년 8월 10일
0

넥스트스텝의 TDD 수업을 들으면서 가장 큰 고민이 있었는데 그건 바로 private 메소드와 랜덤값 테스트이다. 클린코드를 위해 클래스내에서 private 메소드를 사용하게되는데 private특성상 외부에서 사용이 불가한다. 그래서 이를 위한 해법을 찾아보았다.

private method

public class Plus {

    private int plusOne(int number) {
        return number + 1;
    }
}

해결방법

자바 리플렉션

자바 리플렉션은 클래스 자체적으로 검사를 하거나 프로그램의 내부 속성(메소드, 변수 등)을 조작하는 것을 말한다.

@Test
void plusOne() throws Exception {
	Plus plus = new Plus();
    Method plusOneMethod = Plus.class.getDeclaredMethod("plusOne", int.class);
    plusOneMethod.setAccessible(true);
    
    int result = (int) plusOneMethod.invoke(plus, 1);
    assertThat(result).isEqualTo(2);
}

invoke메소드의 파라미터로 인스턴스, private메소드의 파라미터를 넣어주면 된다. invoke메소드의 리턴값은 private메소드의 리턴값과 같고 형변환만 해주면 된다.

리플렉션은 컴파일 과정때 메소드 이름 체크를 하지 못 한다는 단점이 있다.

접근제어자 변경

public class Plus {

    protected int plusOne(int number) {
        return number + 1;
    }
}

매우 간단한 방법이다. private임을 포기해야 하지만 테스트를 할 수 있고 다른 패키지에서는 사용이 불가능한 방법이다.

최선의 방법

최선의 방법은 다름 아닌 테스트 하지 않는 것이다. 단위 테스트는 모든 메소드에 대해서 작성해야 한다고 알고 있었는데 '이게 무슨 소리인가?'라고 생각할 수 있지만, 이 의견을 내뱉은 인물이 한 두명이 아니었다.

Junit의 창시자 Kent Beck은 private 메소드를 테스트 하지말라고 이런 사이트도 만들었다. http://shoulditestprivatemethods.com/

Every time you consider testing a private method, your code is telling you that you haven't allocated responsibilities well.

이 페이지의 소스보기를 하면 나오는 주석인데, 해석해 보자면 "private 메소드 테스트를 고려할 때마다 너의 코드는 제대로 책임을 지고 있지 않다" 라는 뜻이다.

private 메소드는 클래스의 사용자에게 숨겨져야 하는 구현 세부 사항이며 비공개 메서드를 테스트하면 더이상 캡슐화 상태가 아니게 된다. 또한 private 메소드 테스트를 만들었다면, 개발자는 코드를 리팩토링할 때마다 테스트를 신경쓰느라 섣불리 손이 가지 않게 될 것이다.

결론

만약에 private 메소드에 정말로 중요한 로직이 있어서 그것을 꼭 테스트해야 한다면, 어떻게 해야할까? 답은 바로 재설계이다. private 메소드에 있으면 테스트가 힘들기 때문에, 중요 로직은 public이나 protected 메소드에 있는 것이 제대로 된 설계이다.

1개의 댓글

comment-user-thumbnail
2023년 8월 10일

이런 유용한 정보를 나눠주셔서 감사합니다.

답글 달기