2012-02-02 5 views
18

코드 다음과 같은 상상의 orginal 메소드를 호출합니다. 모의 행위를 정의하고 싶습니다. 여기에 메서드를 호출하지 말고 ..... 뭔가 빠졌습니까?Mockito는 실물 감시하는 것은

편집 : 목록은 CGLIB로 장식되어 있습니다. CGLIB 프록시를 제거하면 Mockito가 예상대로 작동합니다. 어떤 아이디어 CGLIB 프록시를 사용할 때 이러한 문제를 해결하는 방법?

감사합니다, 마치에이

+0

사실이 모양은 빌더 패턴을 사용하는 mockito의 구문입니다. (너무 많은 다른 mocking-frameworks처럼) –

+0

Mockito를 아는 한, 코드는 정확합니다. 설명서에 따르면'doThrow'는 void 메소드에만 해당하므로 다시 시도하십시오. 'clear()'를 사용하여 이것이 문제인지 확인하십시오. 그러나 doThrow가 doReturn과 같은 비 void 메소드에서 작동하지 않아야하는 이유를 실제로 상상할 수는 없습니다. – flyx

+0

당신이 여기서 무엇을 묻고 있는지 확실하지 않습니다. 예, void가 아닌 메소드의 경우에도 doThrow()를 사용할 수 있습니다. 문서가 void 메소드를 언급하는 이유는, 스텁 스로우의 두 번째 구문, void 메소드에서는 작동하지 않기 때문에, 그리고 문서에서 doThrow를하기 전에 제시되는 것이기 때문입니다. 당신의 예제에서 get (0)은 스파이에 대해서만 호출되며 실제리스트에는 호출되지 않습니다. 스파이는 doThrow의 컨텍스트에 있음을 알고 있으므로 REAL get (0)을 호출하는 대신 대신 스텁합니다. 네가 묻고있는거야? 그렇다면이 주석을 대답으로 바꿀 것입니다. –

답변

6
import static org.mockito.Mockito.doThrow; 
import static org.mockito.Mockito.spy; 

import java.lang.reflect.Method; 

import org.junit.Test; 

import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 

public class MockitoSpyTest { 

    @Test 
    public void execTest() { 

     System.out.println("*** TEST 1 ***"); 
     System.out.println("Test on unmodified object"); 
     MySet ms = new MySetImpl(); 
     ms.set("test value"); 
     System.out.println("Set contains: " + ms.get()); 

     // decorate ms1 with easymock 
     System.out.println("\n*** TEST 2 ***"); 
     MySet spyMs = spy(ms); 
     doThrow(new NullPointerException("my test nullpointer")).when(spyMs).get(); 
     System.out.println("Test decorated object with SPY"); 
     spyMs.set("test value"); 
     try { 
      System.out.println("Set contains: " + spyMs.get()); 
     } catch (NullPointerException e) { 
      System.out.println("NullPointerException - as expected"); 
     } 

     // Enhance call with CGLIB 
     System.out.println("\n*** TEST 3 ***"); 
     System.out.println("Test on CGLIB decorated object"); 
     Enhancer enc = new Enhancer(); 
     enc.setSuperclass(MySetImpl.class); 
     enc.setInterfaces(new Class[] { MySet.class }); 
     enc.setCallback(new MethodInterceptor() { 

      @Override 
      public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
       if ("get".equals(method.getName())) { 
        System.out.println("CGLIB decorated GET call"); 
       } 
       return proxy.invokeSuper(obj, args); 
      } 
     }); 
     MySet ms1 = (MySet) enc.create(); 
     ms1.set("test value"); 
     System.out.println("Set contains: " + ms1.get()); 

     // decorate ms1 with easymock 
     System.out.println("\n*** TEST 4 ***"); 
     System.out.println("Test on CGLIB decorated object with SPY"); 
     MySet spyMs1 = spy(ms1); 
     doThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get(); 
     spyMs1.set("test value"); 
     System.out.println("Set contains: " + spyMs1.get()); 
    } 

    public interface MySet { 
     void set(String val); 

     String get(); 
    } 

    public static class MySetImpl implements MySet { 
     String val; 

     public void set(String val) { 
      this.val = val; 
      System.out.println("Original SET call:" + val); 
     } 

     public String get() { 

      System.out.println("Original GET call:" + val); 
      return val; 
     } 

    } 
} 

예는 위의 출력을 생성 : - : doThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get();

은 "TEST 4"예상 throw하지 않습니다

*** TEST 1 *** 
Test on unmodified object 
Original SET call:test value 
Original GET call:test value 
Set contains: test value 

*** TEST 2 *** 
Test decorated object with SPY 
Original SET call:test value 
NullPointerException - as expected 

*** TEST 3 *** 
Test on CGLIB decorated object 
Original SET call:test value 
CGLIB decorated GET call 
Original GET call:test value 
Set contains: test value 

*** TEST 4 *** 
Test on CGLIB decorated object with SPY 
CGLIB decorated GET call 
Original GET call:test value 
Original SET call:test value 
CGLIB decorated GET call 
Original GET call:test value 
Set contains: test value 

는 이제 TEST 2TEST 4get 통화 NullPointerException가 발생한다 mockito 스파이를 기반으로 CGLIB가 이미 꾸며져 있기 때문에 예외입니다. CGLIb 호출이 실행 중임을 콘솔에서 볼 수 있습니다 : GLIB decorated GET call 및 스파이 개체를 호출하지 않습니다. CGLIB 프록시와 함께 Spring AOP를 사용할 때도 같은 결과를 얻을 수 있습니다.

+0

우수 사례. 그러나 이것이 어떻게 답이되었는지 나는 알 수 없었다. Mockito와 Spring AOP를 사용할 때 같은 문제가 발생합니다. 나는 내가 감시하는 방법에 대해 스파이 할 수 없었다. – supertonsky

+0

supertonsky, 간단히 말해서 대답은 CgLib 향상된 개체에 Mockito 스파이를 만들 수 없다는 것입니다. :( – bcody

0
Mockito.doThrow(new NullpointerException()).when(spy).get(0); 

여기 문제가이 부분 모의을하려고하고, 그래서 당신은 당신의 테스트 클래스에 주석을해야한다는 생각 :

@PrepareForTest(List.class) 

이것은 작동 할 수도 있고 작동하지 않을 수도 있습니다. 예외 처리를 테스트하는 곳에서 코드를 보았을 때 나는 항상 부분적으로 조롱을받은 것이 아닌 완벽하게 조롱 된 객체에서이 작업을 수행했습니다. 또한 PowerMockito를 부분적 조롱 할 때 광범위하게 사용 했으므로 라이브러리가 필요한 작업을 수행 할 수 있습니다.

+0

혼란스러운 점이 있습니다. **에이.** Mockito는 [Mockito # spy()] (http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#spy (T))를 통해 얼마 동안 부분 모의 작업을 할 수 있습니다. . 그러나 Mockito는 PowerMock이 유용하게 사용될 수있는 최종 수업이나 최종 방법을 모의하지 않습니다. ** B ** ** 당신은'@PrepareForTest (List.class)'에 대해 언급하고 있는데, 그 이유는 두 가지 이유에서 무의미하며 잘못되었다 : 1. List는 인터페이스이기 때문에 조롱하는데 문제가되지 않는다. 2.이 문장만으로 간단히 이겼다. (에이전트를 추가하지 않고) 시스템 클래스에 대해 작업하지 마십시오. – Brice

+0

파워 모의 (power mock)가 다른 프록시를 생성하기 때문에 이것이 가능할 수 있습니다. 나는 그것을 시도하고 javassis 예외를 얻는다.이 경우에는 cglib와 javassis 사이에 충돌이있다. –

+4

너 좋지 않은가? 사람들을 몇 달 뒤에 하향 투표. 1 년 후 API가 변경되면 왜 나를 위해 처벌해야합니까? –