sourcecode

mockito를 사용한 개인 메서드 테스트

copyscript 2022. 9. 22. 00:11
반응형

mockito를 사용한 개인 메서드 테스트

public class A {

    public void method(boolean b){
          if (b == true)
               method1();
          else
               method2();
    }

    private void method1() {}
    private void method2() {}
}

public class TestA {

    @Test
    public void testMethod() {
      A a = mock(A.class);
      a.method(true);
      //how to test like    verify(a).method1();
    }
}

프라이빗 메서드를 어떻게 호출하고, 모키토를 사용하여 프라이빗 메서드를 어떻게 테스트합니까?

모키토로는 불가능합니다.Wiki에서

왜 모키토는 사적인 방법을 조롱하지 않는 거죠?

첫째, 우리는 사적인 방법을 조롱하는 독단적이지 않다.우리는 단지 사적인 방법에는 관심이 없다. 왜냐하면 사적인 방법에는 관심이 없기 때문이다.Mockito가 사적인 방법을 조롱하지 않는 이유는 다음과 같습니다.

Bullet Proof가 아닌 클래스 로더의 해킹이 필요하며 API를 변경합니다(커스텀 테스트 러너를 사용하거나 클래스에 주석을 달아야 합니다.

조작은 매우 간단합니다.방식의 가시성을 프라이빗에서 패키지 보호(또는 보호)로 변경하기만 하면 됩니다.

구현과 유지보수에 시간을 들여야 합니다.포인트 #2와 이미 다른 툴(powermock)로 구현되어 있는 것을 고려하면 이 방법은 의미가 없습니다.

드디어...사적인 방법을 조롱하는 것은 OO의 이해에 문제가 있음을 암시하는 것입니다.OO에서는 메서드가 아닌 객체(또는 역할)가 협업하기를 원합니다.파스칼과 프로시저 코드는 잊으십시오.사물로 생각하다.

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

다음은 PowerMock을 사용하여 수행하는 간단한 예입니다.

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

방법 1을 테스트하려면 코드를 사용합니다.

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);

Mockito는 이 기능을 제공하지 않지만 Mockito + JUnit Reflection Utils 클래스 또는 Spring Reflection을 사용하여 동일한 결과를 얻을 수 있습니다.Test Utils 클래스프라이빗 메서드를 기동하는 방법에 대해서는, 이하에 나타내는 예를 참조해 주세요.

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

Reflection을 사용한 완전한 예TestUtils와 Mockito는 봄을 위한 Mockito라는 책에서 찾을 수 있다.

공식 문서 스프링 테스트

  1. 리플렉션을 사용하면 테스트 클래스에서 개인 메서드를 호출할 수 있습니다.이 경우,

    //테스트 방법은 다음과 같습니다.

    public class TestA {
    
      @Test
        public void testMethod() {
    
        A a= new A();
        Method privateMethod = A.class.getDeclaredMethod("method1", null);
        privateMethod.setAccessible(true);
        // invoke the private method for test
        privateMethod.invoke(A, null);
    
        }
    }
    
  2. 프라이빗 메서드가 다른 프라이빗 메서드를 호출할 경우 오브젝트를 감시하고 다른 메서드를 스터브해야 합니다.시험 수업은 다음과 같습니다.

    //테스트 방법은 다음과 같습니다.

    public class TestA {
    
      @Test
        public void testMethod() {
    
        A a= new A();
        A spyA = spy(a);
        Method privateMethod = A.class.getDeclaredMethod("method1", null);
        privateMethod.setAccessible(true);
        doReturn("Test").when(spyA, "method2"); // if private method2 is returning string data
        // invoke the private method for test
        privateMethod.invoke(spyA , null);
    
        }
    }
    

**반사와 사물을 염탐하는 방법이 있습니다.**private1 및 **private2는 프라이빗 메서드이며 method1은 method2를 호출합니다.

어떤 방법이 있는지가 아니라 행동 측면에서 생각해 보세요.는 '이러한 방법'이라고 불립니다.method만약의 경우에 특별한 행동을 하다b정말이에요.이 경우 동작은 다릅니다.b,, ,, 른, 른, 른, ,, ,, ,, ,, for, for, for, for, for, for, for, for, for, for, for, for, for, for, for, for for, for,method; '1' 입니다. 3가지 테스트3'의 경우 가 아닌method은 용, 1은 용:method1은 용, 1은 용:method2

이와 관련하여 (최근에 다른 SO 스레드에서 제안하고, 그 결과 네 글자로 불렸으니 안심하고 받아들이세요.)메서드 이름보다는 테스트 중인 동작을 반영하는 테스트 이름을 선택하는 것이 도움이 됩니다. 시험이라고 testMethod(),testMethod1(),testMethod2()i i. 는는 like like like 같은 이름을 좋아합니다.calculatedPriceIsBasePricePlusTax() ★★★★★★★★★★★★★★★★★」taxIsExcludedWhenExcludeIsTrue()테스트하는 동작을 나타냅니다.그 후 각 테스트 방법 내에서 표시된 동작만 테스트합니다.대부분의 그러한 행동에는 공개 메서드에 대한 호출이 한 번만 수반되지만, 개인 메서드에 대한 호출이 많이 수반될 수 있습니다.

이게 도움이 됐으면 좋겠다.

사적인 방법을 시험해 보면 안 돼비프라이빗 메서드만 테스트하면 됩니다.비프라이빗 메서드는 프라이빗 메서드를 호출해야 하기 때문입니다.프라이빗 메서드를 테스트하고 싶은 경우는, 설계를 재검토할 필요가 있는 경우가 있습니다.

적절한 의존성 주입을 사용하고 있습니까?개인 메서드를 다른 클래스로 이동하여 테스트해야 합니까?이 방법들은 비공개로 해야 합니까? ...기본값이 되거나 오히려 보호될 수 없습니까?

위의 예에서 '랜덤'이라고 불리는 두 가지 메서드는 실제로 자체 클래스에 배치하여 테스트한 후 위의 클래스에 주입해야 할 수 있습니다.

성찰에 의한 모키토를 사용한 프라이빗한 방법을 내부에서 시험할 수 있었습니다.여기 예가 있습니다.이것이 말이 되도록 이름을 붙이려고 했습니다.

//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));

실제로 Mockito와 함께 개인 멤버로부터 방법을 테스트하는 방법이 있습니다.예를 들어 다음과 같은 클래스가 있다고 가정해 보겠습니다.

public class A {
    private SomeOtherClass someOtherClass;
    A() {
        someOtherClass = new SomeOtherClass();
    }
    public void method(boolean b){
        if (b == true)
            someOtherClass.method1();
        else
            someOtherClass.method2();
    }

}

public class SomeOtherClass {
    public void method1() {}
    public void method2() {}
}

하고 a.method from a a will will will 、 will will 、 will will will will will will will 。SomeOtherClass, 다음과 같은 것을 쓸 수 있습니다.

@Test
public void testPrivateMemberMethodCalled() {
    A a = new A();
    SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
    ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
    a.method( true );

    Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
}

ReflectionTestUtils.setField();감시할 수 있는 걸로 개인 멤버를 찌를 거예요

개인 방식을 테스트해야 하는 이유를 잘 모르겠습니다.근본적인 문제는 공용 메서드가 반환 유형으로 비활성화되어 공용 메서드를 테스트할 수 없다는 것입니다.따라서 개인 메서드를 테스트해야 합니다.제 추측이 맞습니까?

몇 가지 가능한 해결책(AFAIK):

  1. 개인적인 방법을 조롱하지만, 여전히 방법을 "실제로" 테스트하지는 않을 것입니다.

  2. 메서드에서 사용되는 객체의 상태를 확인합니다.대부분 메서드는 입력 값을 일부 처리하고 출력을 반환하거나 개체 상태를 변경합니다.오브젝트의 상태를 테스트하는 것도 사용할 수 있습니다.

    public class A{
    
    SomeClass classObj = null;
    
    public void publicMethod(){
       privateMethod();
    }
    
    private void privateMethod(){
         classObj = new SomeClass();
    }
    
    }
    

    [여기에서는 classObj의 상태변화를 늘에서 늘이 아님으로 체크함으로써 프라이빗 메서드를 테스트할 수 있습니다.]

  3. 코드를 조금 리팩터링합니다(레거시 코드가 아니길 바랍니다).메서드 작성의 기본은 항상 무엇인가를 반환해야 한다는 것입니다(int/부울).반환된 값은 구현에서 사용할 수도 있고 사용하지 않을 수도 있지만 테스트에서 사용할 수도 있습니다.

    코드를 설정합니다.

    public class A
    { 
        public int method(boolean b)
        {
              int nReturn = 0;
              if (b == true)
                   nReturn = method1();
              else
                   nReturn = method2();
        }
    
        private int method1() {}
    
        private int method2() {}
    
    }
    

테스트를 같은 패키지에 넣고 다른 소스 폴더(src/main/java vs. src/test/java)에 넣어 패키지 전용으로 합니다.IMO의 테스트 가능성은 프라이버시보다 더 중요합니다.

개인 메서드가 void가 아닌 경우 외부 종속성 메서드의 매개 변수로 반환 값을 사용하는 경우 종속성을 조롱하고ArgumentCaptor반환값을 캡처합니다.예를 들어 다음과 같습니다.

ArgumentCaptor<ByteArrayOutputStream> csvOutputCaptor = ArgumentCaptor.forClass(ByteArrayOutputStream.class);
//Do your thing..
verify(this.awsService).uploadFile(csvOutputCaptor.capture());
....
assertEquals(csvOutputCaptor.getValue().toString(), "blabla");

@aravind-yarram의 답변을 바탕으로: mockito에서는 불가능합니다.Wiki에서

그렇다면 개인 방법을 테스트하는 OO 방법은 무엇일까요?복잡한 논리를 사용하는 개인 메서드는 클래스가 단일 책임 원칙을 위반하고 있으며 일부 논리를 새로운 클래스로 이동해야 한다는 신호일 수 있습니다.

실제로 이러한 프라이빗 메서드를 보다 세밀한 클래스의 퍼블릭 메서드로 추출함으로써 원래 클래스의 캡슐화를 중단하지 않고 유닛 테스트를 수행할 수 있습니다.

언급URL : https://stackoverflow.com/questions/8799439/testing-private-method-using-mockito

반응형