JUnit으로 private 메소드 테스트하는 방법

Java 테스트 단위로 Junit을 사용되는데, public 메소드 테스트에 대해서는 테스트 코드를 작성하지만, private, protected 메소드의 테스트는 소홀히 하는 경향있다.

화이트박스 테스트는 프로그래머의 의무를 생각하기에, 모든 코드에 대한 테스트가 필요하다. 그래서 모든 메소드 테스트 실시하는 방법을 설명하겠다.

테스트 소스 코드

먼저 테스트 할 코드를 만들어 보겠다.

Sample.java 파일을 생성하여 아래와 같이 작성하자.

public Sample {
    public int add(int x, int y) {
        return (x + y);
    }

    protected int minus(int x, int y) {
        return (x - y);
    }

    private int multiplication(int x, int y) {
        return (x * y);
    }
}

public 메소드 테스트

그리고 public 메소드 “plus"에 대한 테스트 케이스를 아래와 같이 작성한다.

package com.devkuma.tutorial;

import com.devkuma.tutorial.junit.Calc;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.junit.Assert.assertEquals;

public class CalcTest {

    public void plus() {
        Calc calc = new Calc();
        
        int expected = 7;
        
        int actual = calc.plus(5, 2);

        assertEquals(expected, actual);
    }
}

간단한 덧셈의 테스트이다. 성공하는 예제만 있는 평범한 테스트 코드이다.

protected, private 메소드 테스트

인스턴스에서는 protected, private 메소드를 호출할 수 없기 때문에, 자라 리플렉션(reflection)을 이용하여 테스트 케이스를 작성한다.

참고

Sample sample = new Sample();
Method method = Sample.class.getDeclaredMethod("{메소드명}", {인수1}, {인수2}...);
method.setAccessible(true);
int actual = ({반환하는 })method.invoke(<인스턴스>, {인수1}, {인수2}...);

어느 클래스에도 존재하는 class 변수를 사용하여, getDeclaredMethod() 메소드을 사용하여 테스트 메소드를 가져온다.

반환된 메소드의 setAccessible(true)을 설정한다. 이는 외부에서 액세스 할 수 있도록하기 위한 설정이다. 그렇다면 method.invoke() 메소드로 테스트 메소드를 실행한다.

위에 작성한 코드에 protected, private 메소드인 “minus"와 “multiply” 메소드의 테스트 케이스를 추가로 작성해 보자.

package com.devkuma.tutorial;

import com.devkuma.tutorial.junit.Calc;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.junit.Assert.assertEquals;

public class CalcTest {

    public void plus() {
        Calc calc = new Calc();
        
        int expected = 7;
        
        int actual = calc.plus(5, 2);

        assertEquals(expected, actual);
    }

    @Test
    public void minus() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Calc calc = new Calc();
        
        int expected = 3;

        Method method = Calc.class.getDeclaredMethod("minus", int.class, int.class);
        method.setAccessible(true);
        int actual = (int) method.invoke(calc, 5, 2);

        assertEquals(expected, actual);
    }

    @Test
    public void multiply() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Calc calc = new Calc();

        int expected = 10;

        Method method = Calc.class.getDeclaredMethod("multiply", int.class, int.class);
        method.setAccessible(true);
        int actual = (int) method.invoke(calc, 5, 2);

        assertEquals(expected, actual);
    }
    
}

결론

이제 작성한 메소드는 모든 테스트 할 수 있게 되었다.

프로그래머가 버그는 최대의 적이다. 가능한 버그를 최대한 제거를 하도록 노력 합시다.