Java private method test

 

Private Method

클래스내 Private method에 대한 테스트가 필요한 경우가 있다. 하지만 해당 Method를 호출할 수 없어 일반적으로 테스트가 불가능하다. 이러한 경우 어떤 방식으로 테스트를 해야하는지 알아보도록 한다.

// 예시 Class
public class Calculator {

    public int findMaxValue(int[] numbers) {
        int maxValue = Integer.MIN_VALUE;

        for (int i = 0; i < numbers.length; i++) {
            maxValue = max(maxValue, numbers[i]);
        }

        return maxValue;
    }

    private int max(int a, int b) {
        return a > b ? a : b;
    }
}

 

기본 구조

Do not test

Private method는 따로 테스트를 진행하지 않는다. 해당 Private Method는 다른 접근가능 메소드에서 활용된다. 그렇기에 다른 접근 가능 메소드를 테스트하여 처리한다. JUnit의 창시자라 할 수 있는 Kent Beckhttp://shoulditestprivatemethods.com를 트윗하기도 하였다.

public class CalculatorTest {

    Calculator calculator = new Calculator();

    @Test
    public void findMaxValue_sourceGreaterThanTarget_ShouldBeReturnedMaxValue() throws Exception {
        /* GIVEN */
        int[] numbers = {5, 10};

        /* WHEN */
        int maxValue = calculator.findMaxValue(numbers);

        /* THEN */
        assertThat(maxValue, is(10));
    }
}

 

Java Reflection

리플렉션을 활용하여 각종 클래스, 필드, 메소드 등을 찾아 임시적으로 Private을 접근 가능하게 하여 테스트를 진행한다.


public class CalculatorTest {

    Calculator calculator = new Calculator();

    @Test
    public void max_sourceGreaterThanTarget_ShouldBeReturnedSource() throws Exception {
        /* REFLECTION */
        Method maxMethod = Calculator.class.getDeclaredMethod("max", int.class, int.class);
        maxMethod.setAccessible(true);

        /* GIVEN */
        int source = 10;
        int target = 5;

        /* WHEN */
        int maxValue = (int)maxMethod.invoke(calculator, source, target);

        /* THEN */
        assertThat(maxValue, is(source));
    }
}

 

ReflectionTestUtils

Spring Framework에서는 ReflectionTestUtils를 지원해준다.

public class CalculatorTest {

    Calculator calculator = new Calculator();

    @Test
    public void max_sourceGreaterThanTarget_ShouldBeReturnedSource() throws Exception {
        /* GIVEN */
        int source = 10;
        int target = 5;

        /* WHEN */
        int maxValue = ReflectionTestUtils.invokeMethod(calculator, "max", source, target);

        /* THEN */
        assertThat(maxValue, is(source));
    }
}

 

@VisibleForTesting

Google에서 제공하는 자바 공통 라이브러리인 guava에서는 @VisibleForTesting을 지원해준다. 위에서 살펴본 방식과는 달리 테스트를 위해서 패키지내 접근 가능한(Package-private) 메소드로 설정하고, 테스트에 활용한다. 해당 메소드의 접근지정자가 Package-private인 이유를 알리기 위해(가시성) 해당 annotation을 사용한다.

package io.github.yearnlune.private.method.example;

public class Calculator {

    @VisibleForTesting
    int max(int a, int b) {
        return a > b ? a : b;
    }
}
package io.github.yearnlune.private.method.example;

public class CalculatorTest {

    Calculator calculator = new Calculator();

    @Test
    public void max_sourceGreaterThanTarget_ShouldBeReturnedSource() throws Exception {
        /* GIVEN */
        int source = 10;
        int target = 5;

        /* WHEN */
        int maxValue = calculator.max(source, target);

        /* THEN */
        assertThat(maxValue, is(source));
    }
}

Leave a comment