1. 개요

이 예제에서는 개인 메서드를 직접 테스트하는 것이 일반적으로 좋은 생각이 아닌 이유를 간략하게 설명합니다. 그런 다음 필요한 경우 Java에서 개인 메서드를 테스트하는 방법을 보여줍니다.

2. 프라이빗 메소드를 테스트하지 말아야 하는 이유

일반적으로 우리가 작성하는 단위 테스트는 공개 메서드 계약만 확인해야 합니다. 비공개 메서드는 공개 메서드의 호출자가 인식하지 못하는 구현 세부 정보입니다. 또한 구현 세부 정보를 변경해도 테스트가 변경되어서는 안 됩니다.

일반적으로 말해서 비공개 방법을 테스트하도록 촉구하면 다음 문제 중 하나가 강조 표시됩니다.

  • 우리의 개인 방법에는 데드 코드가 있습니다.
  • 우리의 private 메소드는 너무 복잡하고 다른 클래스에 속해야 합니다.
  • 우리의 방법은 처음부터 비공개가 아니었습니다.

따라서 private 메서드를 테스트해야 한다고 느낄 때 실제로 해야 할 일은 근본적인 디자인 문제를 해결하는 것입니다.

3. 예: 비공개 메서드에서 데드 코드 제거

그 간단한 예를 보여드리겠습니다.

우리는 Integer 의 double을 반환하는 private 메소드를 작성할 것 입니다. null 값의 경우 null 을 반환하려고 합니다 .

private static Integer doubleInteger(Integer input) {
    if (input == null) {
        return null;
    }
    return 2 * input;
}

이제 공개 메서드를 작성해 보겠습니다. 클래스 외부의 유일한 진입점이 됩니다.

이 메서드는 Integer 를 입력으로 받습니다. Integer 가 null 이 아닌지 확인합니다.  그렇지 않으면 IllegalArgumentException 이 발생 합니다. 그 후, Integer 값의 두 배를 반환하기 위해 private 메서드를 호출합니다 .

public static Integer validateAndDouble(Integer input) {
    if (input == null) {
        throw new IllegalArgumentException("input should not be null");
    }
    return doubleInteger(input);
}

모범 사례를 따르고 공개 메서드 계약을 테스트해 보겠습니다.

먼저 입력이 null 인 경우 IllegalArgumentException 이 발생하는지 확인 하는 테스트를 작성해 보겠습니다 .

@Test
void givenNull_WhenValidateAndDouble_ThenThrows() {
    assertThrows(IllegalArgumentException.class, () -> validateAndDouble(null));
}

이제 null이 아닌 Integer 가 올바르게 두 배가 되었는지 확인하겠습니다.

@Test
void givenANonNullInteger_WhenValidateAndDouble_ThenDoublesIt() {
    assertEquals(4, validateAndDouble(2));
}

JaCoCo 플러그인이 보고한 적용 범위 를 살펴보겠습니다 .

우리 메소드의 코드 커버리지우리가 볼 수 있듯이 우리의 private 메소드 내부의 null 체크는 우리의 단위 테스트에서 다루지 않습니다. 그럼 테스트 해볼까요?

내 대답은 아니오 야. 우리의 사적인 방법은 진공 상태에서 존재하지 않는다는 것을 이해하는 것이 중요합니다. 공개 메서드에서 데이터가 검증된 후에만 호출됩니다. 따라서 개인 메서드의 null 검사에 도달하지 않습니다. 죽은 코드이므로 제거해야 합니다.

4. 자바에서 프라이빗 메소드를 테스트하는 방법

우리가 낙심하지 않았다고 가정하고, 우리의 private 메소드를 구체적으로 테스트하는 방법을 설명하겠습니다.

이를 테스트하려면 private 메소드에 다른 가시성이 있으면 도움이 될 것 입니다. 좋은 소식은 리플렉션 을 사용하여 이를 시뮬레이션할 수 있다는 것입니다 .

우리의 캡슐화 클래스는 Utils 라고 합니다. 아이디어는 정수 를 매개변수로 받아들이는 doubleInteger 라는 개인 메서드에 액세스하는 것입니다. 그런 다음 Utils 클래스 외부에서 액세스할 수 있도록 가시성을 수정합니다 . 어떻게 할 수 있는지 봅시다.

private Method getDoubleIntegerMethod() throws NoSuchMethodException {
    Method method = Utils.class.getDeclaredMethod("doubleInteger", Integer.class);
    method.setAccessible(true);
    return method;
}

이제 우리는 이 방법을 사용할 수 있습니다. null 객체가 주어지면 private 메서드가 null 을 반환 하는지 확인하는 테스트를 작성해 보겠습니다 . null 이 될 매개변수에 메서드를 적용해야 합니다 .

@Test
void givenNull_WhenDoubleInteger_ThenNull() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
    assertEquals(null, getDoubleIntegerMethod().invoke(null, new Integer[] { null }));
}

invoke 메소드 의 사용법에 대해 조금 더 설명하겠습니다 . 첫 번째 인수는 메서드를 적용하는 개체입니다. doubleInteger 는 정적이므로 null을 전달 했습니다 . 두 번째 인수는 매개변수의 배열입니다. 이 경우 매개변수가 하나만 있었고 null 이었습니다 .

마지막으로 null이 아닌 입력의 경우도 테스트할 수 있는 방법을 보여 드리겠습니다.

@Test
void givenANonNullInteger_WhenDoubleInteger_ThenDoubleIt() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    assertEquals(74, getDoubleIntegerMethod().invoke(null, 37));
}

5. 결론

이 기사에서 우리는 왜 private 메소드를 테스트하는 것이 일반적으로 좋은 생각이 아닌지 배웠습니다. 그런 다음 Java에서 private 메소드를 테스트하기 위해 리플렉션을 사용하는 방법을 시연했습니다.

항상 그렇듯이 코드는 GitHub 에서 사용할 수 있습니다 .

Junit footer banner