|
|
Zeile 1: |
Zeile 1: |
| [[Kategorie:Java]] | | [[Kategorie:Java]] |
| [[Kategorie:Mockito]] | | [[Kategorie:Mockito]] |
| = Mock vs. Spy = | | == Voraussetzungen == |
| Neben dem hier beschriebenen Mocks giebt es ein weiteres Konzept in Mockito, das dem Mocki sehr ähnlich ist: der Spy.
| | Die Voraussetzungen für die Anwendung von {{java|verify}} sind simpel. |
| Bei einem Spy handelt es sich um ein Objekt, das um ein anderes Objekt herumgewickelt wird. Gewöhnlich wird es verwendet
| | Man benötigt dazu einen Mock oder einen Spy der ein "echtes" Objekt umwickelt. |
| um Laufzeit-Informationen über das Objekt zu sammeln. Man kann damit etwa überprüfen, ob eine Methode des Objekts aufgerufen
| | Mocks und Spies werden [[Partieller Mock|hier]] beschrieben. |
| wurde oder nicht -- sehr praktisch in Unit-Tests. Ein Spy wird so erzeugt:
| | |
| | == Die grundsätzliche Anwendung == |
| | Wir stellen uns hier einen Handler vor, dessen {{java|onMessage}}-Methode die {{java|send}}-Methode |
| | des {{java|WebSocketConnection}}-Objekts aufrufen soll. |
| {{java|code= | | {{java|code= |
| Foo foo = new Foo();
| | @Test |
| Foo spiedFoo = Mockito.spy(foo);
| | public void auftragNullSendetFehlermeldung() { |
| | WebSocketConnection connection = Mockito.mock(WebSocketConnection.class); |
| | handler.onMessage(connection, (String) null); |
| | Mockito.verify(connection, Mockito.atLeastOnce()).send("Die Anfrage kann nicht verarbeitet werden."); |
| }} | | }} |
| Im Gegensatz zum Mock benötigt der Spy für die Erzeugung ein Objekt. Das entstehende Spy-Objekt hat den gleichen Typ
| | Die ersten beiden Zeilen führen den Test durch, die dritte Zeile prüft, daß die {{java|send}}-Methode |
| wie das umwickelte Objekt. Wie der Mock entsteht dabei eine Unterklasse. Einen Mock braucht man nicht mit einem Spy zu
| | mit dem angegebenen Text mindestens einmal aufgerufen wird. |
| umwickeln, er hat bereits die gleiche Funktionalität die der Spy erzeugt. Im Folgenden geht es um die unterschiedliche
| |
| Verwendung von Mock und Spy, Für die Untersuchung des Aufrufverhaltens giebt es eine eigene Seite.
| |
|
| |
|
| = Zwei extreme Mocks =
| | Der erste Parameter von {{java|verify}} ist das zu untersuchende Objekt. Der zweite Parameter giebt die das erwartete |
| Die Klasse, die hier mit der mock-Methode erzeugt wird
| | Ergebnis an. Auf das Ergebnis wird die Methode aufgerufen, deren Aufruf überprüft werden soll. |
| {{java|code=Echt mock = Mockito.mock(Echt.class);}}
| |
| ersetzt alle Methoden der Klasse {{java|Echt}} durch gemockte Methoden. Man kann also getrost von einem ''totalen Mock''
| |
| sprechen. Ein Objekt der Klasse {{java|Echt}} ist ein gewissermaßen ein ''echtes'' Objekt und hingegen erwartungsgemäß keine
| |
| einzige Methode der Klasse. Man könnte in ihr einen entartetetn Mock sehen und als ''Null-Mock'' bezeichnen.
| |
|
| |
|
| Objekte der originalen Klasse können nicht unmittelbar mit Mockito manipuliert werden, man umwickelt sie daher mit
| | Das gleiche {{java|verify}} würde auch funktioneren, wenn statt des Mocks eine echte Connection erzeugt um mit spy |
| einem Mockito-Proxy-Objekt, einem Spy:
| | ummantelt würde: |
| {{java|code=Echt spy = Mockito.spy(new Echt());}} | | {{java|code=WebSocketConnection connection = Mockito.spy(new MyWebSocketConnectionImplementation());}} |
| Zwischen diesen beiden Extremen, dem "Alles" des totalen Mock und dem "Nichts" des Null-Mock liegt ein weites
| |
| Feld von Möglichkeiten um Teile der Original-Klasse durch mock-Methoden zu ersetzt und Teile davon unberührt
| |
| zu lassen: das sind die partiellen Mocks.
| |
|
| |
|
| Um einen partiellen Mock zu bauen gibt es zwei diametrale Vorgehensweisen: Entweder man beginnt beim totalen
| | == Prüfungen == |
| Mock und läßt einzelne Methoden die Funktionalität der Original-Klasse ausführen; oder man beginnt beim Null-Mock
| | :'''atLeastOnce''' |
| und mockt einzelne Methoden, deren originale Funktionalität nicht ausgeführt werden soll. Für welches Vorgehen
| | :: Die Methode wurde mindestens einmal aufgerufen |
| man sich entscheidet hängt vom Anwendungsfall ab.
| |
|
| |
|
| == Den totalen Mock aufweichen ==
| | :'''times(n)''' |
| die Klasse {{java|Echt}} sei so definiert:
| | :: Die Methode wurde ''n'' mal aufgerufen |
| {{java|code=
| |
| class Echt {
| |
| int eins() {
| |
| return 1;
| |
| }
| |
| int zwei(int x) {
| |
| return x + 3;
| |
| }
| |
| }
| |
| }}
| |
| Der eingangs erzeugte Mock mockt beide Methoden. Die Methode {{java|eins}} soll nun ''nicht mehr'' gemockt werden,
| |
| das geht so:
| |
| {{java|code=
| |
| Echt mock = Mockito.mock(Echt.class);
| |
| Mockito.when(mock.eins()).thenCallRealMethod();
| |
| }}
| |
| Mehr ist dazu eigentlich nicht zu sagen. Der Aufruf von {{java|eins()}} liefert nun wie erwartet den Wert ''1'', während der
| |
| Aufruf von {{java|zwei()}} für jedes Argument den Wert ''0'' liefert.
| |
| Man hat nun für jede Methode drei Möglichkeiten die man nach belieben anwenden kann:
| |
| *Nichts tun und die gemockte Methode behalten
| |
| *Die echte Methode der Superklasse aufrufen
| |
| *Die Methode mit speziellem Mock-Verhalten ausstatten
| |
| Die Mock-Anweisungen lassen sich beliebig mischen, wie dieses Beispiel mit Methode {{java|zwei}} der Klasse {{java|Echt}} zeigt:
| |
| {{java|code=
| |
| Echt mock = Mockito.mock(Echt.class);
| |
| Mockito.when(mock.drei(Mockito.anyInt())).thenCallRealMethod();
| |
| Mockito.when(mock.drei(Mockito.eq(5))).thenReturn(4711);
| |
| }}
| |
| Bei Aufruf von {{java|mock.zwei(5)}} erhalten wir den Wert ''4711'' aus dem Mock und in allen anderen Fällen das Ergebnis
| |
| der echten Methode. Auch hier ist zu beachten, daß allgemeinere Matcher vor spezielleren Matchern kommen.
| |
| In diesem Falle also {{java|.anyInt()}} vor {{java|.eq(5)}}.
| |
|
| |
|
| == Den Null-Mock aushöhlen ==
| | :'''times(0)''' oder '''never()''' |
| Wir beginnen nun mit dem Spy, der als Null-Mock das komplette Original-Verhalten der Klasse {{java|Echt erhält}}.
| | :: Die Methode wurde nicht aufgerufen |
| Diesmal möchten wir die Methode {{java|eins}} mocken, während die Methode {{java|zwe)}} weiterhin das reale Verhalten aufweist:
| |
| {{java|code=
| |
| Echt spy= Mockito.spy(new Echt());
| |
| Mockito.when(spy.eins()).thenReturn(3);
| |
| }}
| |
| Und fertig ist die Laube.
| |
Voraussetzungen
Die Voraussetzungen für die Anwendung von verify
sind simpel.
Man benötigt dazu einen Mock oder einen Spy der ein "echtes" Objekt umwickelt.
Mocks und Spies werden hier beschrieben.
Die grundsätzliche Anwendung
Wir stellen uns hier einen Handler vor, dessen onMessage
-Methode die send
-Methode
des WebSocketConnection
-Objekts aufrufen soll.
@Test
public void auftragNullSendetFehlermeldung() {
WebSocketConnection connection = Mockito.mock(WebSocketConnection.class);
handler.onMessage(connection, (String) null);
Mockito.verify(connection, Mockito.atLeastOnce()).send("Die Anfrage kann nicht verarbeitet werden.");
Die ersten beiden Zeilen führen den Test durch, die dritte Zeile prüft, daß die send
-Methode
mit dem angegebenen Text mindestens einmal aufgerufen wird.
Der erste Parameter von verify
ist das zu untersuchende Objekt. Der zweite Parameter giebt die das erwartete
Ergebnis an. Auf das Ergebnis wird die Methode aufgerufen, deren Aufruf überprüft werden soll.
Das gleiche verify
würde auch funktioneren, wenn statt des Mocks eine echte Connection erzeugt um mit spy
ummantelt würde:
WebSocketConnection connection = Mockito.spy(new MyWebSocketConnectionImplementation());
Prüfungen
- atLeastOnce
- Die Methode wurde mindestens einmal aufgerufen
- times(n)
- Die Methode wurde n mal aufgerufen
- times(0) oder never()
- Die Methode wurde nicht aufgerufen