2012-01-25 18 views
8

Próbuję wyśmiać niektóre metody oparte na refleksji. Poniżej można zobaczyć szczegóły,Wyśmiewające połączenia oparte na odbiorze

klasę badanego

public class TracerLog { 
    @AroundInvoke 
    public Object logCall(InvocationContext context) throws Exception { 
     Logger logger = new Logger(); 
     String message = "INFO: Invoking method - " 
       + context.getMethod().getName() + "() of Class - " 
       + context.getMethod().getDeclaringClass(); 

     logger.write(message); 
     return context.proceed(); 
    } 
} 

test

public class TracerLogTest { 

@Mock 
InvocationContext mockContext; 
@Mock 
Logger mockLogger; 
@InjectMocks 
private TracerLog cut = new TracerLog(); 

@BeforeMethod 
public void setup() { 
    MockitoAnnotations.initMocks(this); 
} 

@Test 
public void logCallTest() throws Exception { 
    when(mockContext.proceed()).thenReturn(true); 
    when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass"); 
    cut.logCall(mockContext); 
    verify(mockContext).proceed(); 
} 

}

lub

@Test 
public void logCallTest() throws Exception { 
    when(mockContext.proceed()).thenReturn(true); 
    when(mockContext.getMethod().getName()).thenReturn("someMethod"); 
    when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass"); 
    cut.logCall(mockContext); 
    verify(mockLogger).write(anyString()); 
    verify(mockContext).proceed(); 
} 

Ale z testów zakończy się niepowodzeniem z NullPointerException . Rozumiem, że robię coś złego przeciwko kpiącym koncepcjom, ale nie rozumiem, co to jest. Czy możesz rzucić trochę światła na to, a także zasugerować mi, jak można tę metodę przetestować?

Dzięki.

+0

W jaki sposób tworzysz swoje fałszywe obiekty i testowany obiekt? Czy możesz opublikować całą swoją klasę testową, a nie tylko metodę testową? Dzięki. –

+0

@DavidWallace Edytowałem teraz pytanie, aby dołączyć cały kod. – Bala

Odpowiedz

17

Potrzebujesz obiektu Method i obiektu Class. Jak na twój komentarz, Mockito nie może kpić z Metody, więc potrzebujesz prawdziwego. Nie testowałem tego, ale wierzę, że to zadziała. Zamiast:

when(mockContext.getMethod().getName()).thenReturn("someMethod"); 
when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass"); 

potrzebował:

// any method will do, but here is an example of how to get one. 
Method testMethod = this.getClass().getMethod("logCallTest"); 

when(mockContext.getMethod()).thenReturn(testMethod); 

Oczywiście getName() nie powróci „metodę someMethod” już i getDeclaringClass().getName() zwróci nazwę tej klasy testowej (w tym przykładzie), ale mimo, że mogłem Wybierając to, co powracają, to, co zwracają, jest nadal deterministyczne, więc powinieneś być w stanie zweryfikować wszystko, czego potrzebujesz. (Oczywiście, gdybyś musiał szpiegować lub sprawdzić, czy wywołanie zostało wykonane na samym obiekcie Method, nadal utkniesz.)

+0

Dziękuję za odpowiedź, ale Mockito skarży się, że nie może kpić lub szpiegować java.lang.reflect.Method. Czy istnieją inne sposoby, aby to osiągnąć? – Bala

+0

Edytowałem swoją odpowiedź, aby pokazać, jak korzystać z prawdziwego obiektu Method. Powinno to dotyczyć prostych przykładów z twojego pytania, ale wciąż istnieją ograniczenia. – jhericks

+0

Dzięki za sugestię, ale metoda mockContext.getMethod(). GetDeclaringClass() nie będzie działać w tym przypadku. – Bala

3

Tak, problem polega na tym, że mockContext.getMethod() zwróci wartość null. Więc za każdym razem, gdy to uruchomisz, wywołaj coś na wynik (getDeclaringClass() lub getName()), otrzymasz NPE. Prawdopodobnie chcesz użyć domyślnej odpowiedzi RETURNS_DEEP_STUBS, kiedy konfigurujesz symulację. Coś takiego, jak powinno powinno wystarczyć, aby wykonać tę operację.

+0

Witam David W większości się z tobą zgadzam. Ale dla czytelnika: metoda jest ostateczną klasą, nie można z niej kpić z Mockito;) Nie polecałbym też kpić z typów, których nie posiadasz. – Brice

+0

Oh kłopot. Brice ma rację (zazwyczaj tak jest, o tych rzeczach). Ponieważ Mockito nie może kpić z finałowych zajęć, nie widzę sposobu, aby zrobić to, co chciał oryginalny plakat. Przepraszam. –

+0

@Brice Cóż, zgadzam się z tobą, ale InvocationContext nie jest ostateczną klasą i musi być wyśmiewany w moim przypadku, ponieważ nie chcę, aby serwer aplikacji był uruchomiony dla mojego testu. Czy gdzieś poszedłem źle? – Bala

Powiązane problemy