2012-07-23 7 views
201

Ich benutze Mockito 1.9.0. Ich möchte das Verhalten für eine einzelne Methode einer Klasse in einem JUnit-Test verspotten, so habe ichMockito: Versucht, Methode auszuspionieren ruft die ursprüngliche Methode

final MyClass myClassSpy = Mockito.spy(myInstance); 
Mockito.when(myClassSpy.method1()).thenReturn(myResults); 

Das Problem ist, in der zweiten Zeile wird myClassSpy.method1() eigentlich immer genannt, in Ausnahmefällen führt. Der einzige Grund, warum ich Mocks verwende, ist, dass später, wenn myClassSpy.method1() aufgerufen wird, die echte Methode nicht aufgerufen wird und das myResults Objekt zurückgegeben wird.

MyClass ist eine Schnittstelle und myInstance ist eine Implementierung davon, wenn das zählt.

Was muss ich tun, um dieses Spionageverhalten zu korrigieren?

Antwort

348

mich the official documentation Lassen Sie zitieren:

Wichtige Gotcha auf reale Objekte Spionage!

Manchmal ist es unmöglich zu verwenden, wenn (Objekt) für Stubbing Spies. Beispiel:

List list = new LinkedList(); 
List spy = spy(list); 

// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty) 
when(spy.get(0)).thenReturn("foo"); 

// You have to use doReturn() for stubbing 
doReturn("foo").when(spy).get(0); 

In Ihrem Fall geht es so etwas wie:

doReturn(resulstIWant).when(myClassSpy).method1(); 
+15

Was passiert, wenn ich diese Methode benutze und mein Original wird immer noch angerufen? Könnte es Probleme mit Parametern geben, die ich bestanden habe? Hier ist der ganze Test: http://pastebin.com/ZieY790P 'send' Methode heißt –

+9

@EvgeniPetrov, wenn Ihre ursprüngliche Methode immer noch aufgerufen wird, ist es wahrscheinlich, weil Ihre ursprüngliche Methode endgültig ist. Mockito verspottet keine finalen Methoden und kann Sie nicht vor dem Spott der finalen Methoden warnen. – MarcG

+0

ist dies auch für doThrow() möglich? – Gobliins

19

Mein Fall von der akzeptierten Antwort anders war. Ich habe versucht, eine Paket-private Methode für eine Instanz zu verspotten, die nicht

package common; 

public class Animal { 
    void packageProtected(); 
} 

package instances; 

class Dog extends Animal { } 

und die Testklassen in diesem Paket lebten

package common; 

public abstract class AnimalTest<T extends Animal> { 
    @Before 
    setup(){ 
    doNothing().when(getInstance()).packageProtected(); 
    } 

    abstract T getInstance(); 
} 

package instances; 

class DogTest extends AnimalTest<Dog> { 
    Dog getInstance(){ 
    return spy(new Dog()); 
    } 

    @Test 
    public void myTest(){} 
} 

Die Zusammenstellung ist richtig, aber wenn es versucht, die Einrichtung der testen Sie stattdessen die echte Methode.

Deklarieren der Methode oder öffentlichen behebt das Problem geschützt, tho es keine saubere Lösung ist.

+0

Ich stieß auf ein ähnliches Problem, aber die Test-und Paket-private Methode waren im selben Paket. Ich denke, Mockito hat Probleme mit paket-privaten Methoden im Allgemeinen. – Dave

7

Die Antwort von Tomasz Nurkiewicz scheint nicht die ganze Geschichte zu erzählen!

NB Mockito Version: 1.10.19.

Ich bin sehr ein Mockito newb, kann also das folgende Verhalten nicht erklären: Wenn es einen Experten da draußen gibt, der diese Antwort verbessern kann, fühlen Sie sich bitte frei.

Verfahren in Frage hier, getContentStringValue ist NICHTfinal und NICHTstatic.

Diese Linie tutgetContentStringValue die ursprüngliche Methode aufrufen:

doReturn("dummy").when(im).getContentStringValue(anyInt(), isA(ScoreDoc.class)); 

Diese Linie nicht Aufruf der ursprünglichen Methode getContentStringValue:

doReturn("dummy").when(im).getContentStringValue(anyInt(), any(ScoreDoc.class)); 

Aus Gründen, die ich beantworten kann nicht, Die Verwendung von isA() führt dazu, dass das beabsichtigte (?) "do not call method" -Verhalten von doReturn fehlschlägt.

Schauen wir uns die hier beteiligten Methodensignaturen an: Sie sind beide static Methoden von Matchers. Beide werden vom Javadoc gesagt, dass sie null zurückgeben, was ein wenig schwierig ist, sich selbst zu verstehen. Vermutlich wird das Class Objekt, das als der Parameter übergeben wird, untersucht, aber das Ergebnis wird entweder nie berechnet oder verworfen. Vorausgesetzt, dass null für jede Klasse stehen kann und Sie hoffen, dass die verspottete Methode nicht aufgerufen wird, konnten die Signaturen von isA(...) und any(...) einfach null anstelle eines generischen Parameters zurückgeben * <T>?

Wie dem auch sei:

public static <T> T isA(java.lang.Class<T> clazz) 

public static <T> T any(java.lang.Class<T> clazz) 

Die API-Dokumentation geben keine Ahnung darüber. Es scheint auch zu sagen, dass die Notwendigkeit eines solchen Verhaltens "nicht anrufen" "sehr selten" ist. Persönlich verwende ich diese Technik die ganze Zeit: in der Regel finde ich, dass Mocking beinhaltet ein paar Zeilen, die "die Szene" ... gefolgt von einem Aufruf einer Methode, die dann "spielt" die Szene in den Schein Kontext, die Sie inszeniert haben ... und während du die Szenerie und die Requisiten einrichtest ist das letzte, was du willst, dass die Schauspieler die Bühne verlassen und anfangen, ihre Herzen zu spielen ...

Aber das ist weit über meine Gehaltsstufe hinaus .. Ich lade Erklärungen von jedem vorbeikommenden Mockito-Hohepriester ein ...

* ist "allgemeiner Parameter" der rechte Ausdruck?

+0

Ich weiß nicht, ob dies Klarheit bringt oder die Sache weiter verwirrt, aber der Unterschied zwischen isA() und any() besteht darin, dass A tatsächlich Typprüfungen durchführt, während jede() Familie von Methoden einfach erstellt wurde, um das Casting zu vermeiden das Argument. –

+0

@KevinWelker Danke. Und tatsächlich fehlen die Methodennamen nicht in einer bestimmten selbsterklärenden Qualität. Ich stelle jedoch, und wie mild auch immer, die genialen Mockito-Designer in Frage, weil sie nicht angemessen dokumentiert sind. Zweifellos muss ich noch ein Buch über Mockito lesen. PS tatsächlich scheint es sehr wenig Ressourcen zu geben, um "intermediate Mockito" zu unterrichten! –

+1

Die Geschichte ist, dass die anyXX-Methoden zuerst erstellt wurden, um nur mit Typcasting umzugehen. Wenn dann vorgeschlagen wurde, dass sie die Argumentprüfung hinzufügen, wollten sie die Benutzer der vorhandenen API nicht trennen und erstellten daher die Familie isA(). Wissend, dass die any() -Methoden die Typüberprüfung durchgeführt haben sollten, verzögerten sie diese Änderungen, bis sie andere brechende Änderungen in der Mockito 2.X-Überholung einführten (was ich noch nicht ausprobiert habe). In 2.x + sind anyX() -Methoden Aliase für die isA() - Methoden. –

1

In meinem Fall musste ich mit Mockito 2.0 alle any() -Parameter in Nullable() ändern, um den echten Aufruf zu stubben.

+0

Lass dich nicht von der 321 zur besten Antwort hinreißen, das hat mein Problem gelöst :) Ich kämpfe seit ein paar Stunden damit! –

0

Ich habe noch einen weiteren Grund für Spion gefunden, die ursprüngliche Methode zu nennen.

Jemand hatte die Idee, eine final Klasse zu verspotten und fand über MockMaker:

Da dies anders zu unseren derzeitigen Mechanismus funktioniert und diese unterschiedliche Einschränkungen und wie wir Erfahrung und Nutzer-Feedback sammeln möchten, Diese Funktion musste explizit aktiviert werden, um verfügbar zu sein. es kann src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker, indem Sie die Datei über den Mockito Erweiterungsmechanismus durchgeführt werden, um eine einzelne Zeile enthält: mock-maker-inline

Quelle: https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

Nachdem ich fusionierte und brachte diese Datei auf meinem Rechner, konnte meine Tests.

Ich musste nur die Linie (oder die Datei) entfernen, und spy() funktioniert.