[java] mockito를 사용한 Private 메서드 테스트

공개 클래스 A {

    public void method (boolean b) {
          if (b == true)
               method1 ();
          그밖에
               method2 ();
    }

    private void method1 () {}
    private void method2 () {}
}
public class TestA {

    @테스트
    public void testMethod () {
      A a = mock (A.class);
      a.method (true);
      // verify (a) .method1 ();과 같이 테스트하는 방법
    }
}

비공개 메소드를 테스트하는 방법은 호출 여부와 mockito를 사용하여 비공개 메소드를 테스트하는 방법은 무엇입니까 ???



답변

Mockito로는 그렇게 할 수 없지만 Powermock 을 사용하여 Mockito 를 확장하고 개인 메서드를 모의 할 수 있습니다 . Powermock은 Mockito를 지원합니다. 여기 에 예가 있습니다.


답변

mockito를 통해서는 불가능합니다. 자신의에서 위키

Mockito가 개인 메서드를 조롱하지 않는 이유는 무엇입니까?

첫째, 우리는 사적인 방법을 조롱하는 것에 대해 독단적이지 않습니다. 우리는 private 메서드를 테스트하는 관점에서 볼 때 private 메서드가 존재하지 않기 때문에 신경 쓰지 않습니다. Mockito가 개인 메서드를 모의하지 않는 몇 가지 이유는 다음과 같습니다.

방탄이 아닌 클래스 로더를 해킹해야하며 API를 변경해야합니다 (사용자 지정 테스트 실행기를 사용하고 클래스에 주석을 추가해야 함).

해결 방법은 매우 쉽습니다. 메서드의 가시성을 비공개에서 패키지 보호 (또는 보호)로 변경하기 만하면됩니다.

이를 구현하고 유지하는 데 시간을 투자해야합니다. 그리고 포인트 # 2와 그것이 이미 다른 도구 (powermock)에서 구현되었다는 사실은 의미가 없습니다.

마지막으로 … 비공개 메소드를 조롱하는 것은 OO의 이해에 문제가 있다는 힌트입니다. OO에서는 메소드가 아닌 객체 (또는 역할)가 협업하기를 원합니다. 파스칼 및 절차 적 코드는 잊어 버리십시오. 사물에서 생각하십시오.


답변

다음은 powermock 으로 수행하는 방법에 대한 작은 예입니다.

public class Hello {
    private Hello obj;
    private Integer method1(Long id) {
        return id + 10;
    }
} 

method1 을 테스트하려면 코드를 사용하십시오.

Hello testObj = new Hello();
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));

개인 개체 obj 를 설정하려면 다음을 사용하십시오.

Hello testObj = new Hello();
Hello newObject = new Hello();
Whitebox.setInternalState(testObj, "obj", newObject);


답변

어떤 방법이 있는지가 아니라 행동의 관점에서 생각해보십시오. 호출 된 메서드 는 true 인 method경우 특정 동작을 b합니다. b거짓 이면 다른 동작을합니다 . 이것은 두 개의 다른 테스트를 작성해야 함을 의미합니다 method. 각 경우에 하나씩. 따라서 세 가지 방법 지향 테스트 (하나는 method, 하나는 method1, 하나는 method2, 행동 지향 테스트는 두 개)가 있습니다.

이것과 관련이 있습니다 (최근에 다른 SO 스레드에서 이것을 제안했고 결과적으로 4 글자 단어로 불렸으므로 소금 한 알로 자유롭게 가져 가십시오.) 메서드 이름이 아닌 테스트중인 동작을 반영하는 테스트 이름을 선택하는 것이 도움이됩니다. 따라서 테스트 testMethod(), testMethod1()등을 부르지 마십시오 testMethod2(). 같은 이름과 같은 I calculatedPriceIsBasePricePlusTax()또는 taxIsExcludedWhenExcludeIsTrue()내가 테스트하고있는 무슨 행동을 나타내는 것을; 그런 다음 각 테스트 방법 내에서 표시된 동작 만 테스트합니다. 대부분의 이러한 동작에는 공용 메서드에 대한 한 번의 호출 만 포함되지만 개인 메서드에 대한 많은 호출이 포함될 수 있습니다.

도움이 되었기를 바랍니다.


답변

Mockito는 이러한 기능을 제공하지 않지만 Mockito + JUnit ReflectionUtils 클래스 또는 Spring ReflectionTestUtils 클래스를 사용하여 동일한 결과를 얻을 수 있습니다 . 여기 에서 개인 메서드를 호출하는 방법을 설명하는 아래 예제를 참조하십시오 .

ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");

ReflectionTestUtils 및 Mockito를 사용한 전체 예제는 Mockito for Spring 책에서 찾을 수 있습니다.


답변

개인 메서드를 테스트한다고 가정하지 않습니다. 어쨌든 비공개 메소드를 호출해야하므로 비공개가 아닌 메소드 만 테스트해야합니다. 비공개 메서드를 테스트하고 싶다면 디자인을 재고해야한다는 의미 일 수 있습니다.

적절한 종속성 주입을 사용하고 있습니까? 개인 메서드를 별도의 클래스로 이동하고 테스트해야 할 수도 있습니까? 이러한 방법은 비공개 여야합니까? … 기본 또는 보호되지 않을 수 있습니까?

위의 경우 “무작위”라고하는 두 메서드는 실제로 자체 클래스에 배치하고 테스트 한 다음 위의 클래스에 주입해야 할 수 있습니다.


답변

리플렉션을 사용하여 mockito를 사용하여 내부의 개인 메서드를 테스트 할 수있었습니다. 여기에 예가 있습니다.

//Service containing the mock method is injected with mockObjects

@InjectMocks
private ServiceContainingPrivateMethod serviceContainingPrivateMethod;

//Using reflection to change accessibility of the private method

Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
    Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
    //making private method accessible
    m.setAccessible(true);
    assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));