Mockito: Einführung: Unterschied zwischen den Versionen

Aus MimiPedia
(Die Seite wurde neu angelegt: „Category:Java Category:Mockito = Einführung = Ein Mock – im Sinne dieser Eiführung – ist ein Objekt, das so aussieht aber sich nicht so verhält…“)
 
Zeile 2: Zeile 2:
[[Category:Mockito]]
[[Category:Mockito]]
= Einführung =
= Einführung =
Ein Mock – im Sinne dieser Eiführung – ist ein Objekt, das so aussieht aber sich nicht so verhält wie das "echte" Objekt das es ersetzt.
Ein Mock – im Sinne dieser Einführung – ist ein Objekt, das so aussieht aber sich nicht so verhält wie das "echte" Objekt das es ersetzt.
Man kann sich das vorstellen wie eine Theater-Requisite: Benötigt man auf der Bühne ein Buch, verwendet man einen Pappkarton,
Man kann sich das vorstellen wie eine Theater-Requisite: Benötigt man auf der Bühne ein Buch, verwendet man einen Pappkarton,
der von außen aussieht wie ein Buch aber keines ist. So versteht diese Einführung unter einem "Mock" -- salopp ausgedrückt:
der von außen aussieht wie ein Buch aber keines ist. So versteht diese Einführung unter einem "Mock" -- salopp ausgedrückt:

Version vom 21. April 2021, 20:28 Uhr

Einführung

Ein Mock – im Sinne dieser Einführung – ist ein Objekt, das so aussieht aber sich nicht so verhält wie das "echte" Objekt das es ersetzt. Man kann sich das vorstellen wie eine Theater-Requisite: Benötigt man auf der Bühne ein Buch, verwendet man einen Pappkarton, der von außen aussieht wie ein Buch aber keines ist. So versteht diese Einführung unter einem "Mock" -- salopp ausgedrückt:

ein Objekt, das ein anderes ersetzt und dabei das originale Objekt in bestimmten Aspekten nachahmen kann,

aber niemals dessen vollständige Funtionalität hat. Es kann Funktionalität und Seiteneffekte hinzufügen falls erforderlich.

Tatsächlich ist die Verwendung der Begriffe Dummy, Fake, Stub und Mock durchaus uneinheitlich. Für diese Einführung verzichten wir auf eine akademische Unterscheidung, gehen pragmatisch vor, sprechen durchgehend vom "Mock" und meinen das oben genannte. Dem Sprachenthusiasten, der an einer genaueren Definition interessiert ist, sei zum Einstieg der Blog-Artikel von Martin Fowler empfohlen.

Aufgaben

Ein Mock kann bei der Implementierung von Unit-Tests für verschiedene Aufgaben genutzt werden. Man kann diese Aufgaben in der Regel auch anders lösen, aber wir möchten hier natürlich erörtern wie Mockito uns bei der Erfüllung unterstützen kann.

Typische Aufgaben für Mocks sind

  • Das Emulieren von Klassen, deren wahre Funktionalität nicht ausgeführt werden kann, darf oder soll
  • Das Erzeugen von Instanzen von Interfaces und Klassen, von denen keine konkrete Implementierung erzeugt werden kann
  • Der Überprüfung, ob –- und mit welchen Argumenten -– Methoden einer Klasse aufgerufen wurden.

So tun als täte es: Jeder Unit-Test muß isoliert und ohne externe Abhängigkeiten ausgeführt werden können. Es reicht nicht, wenn der Test lokal im Eclipse läuft, er muß auch jederzeit vom Jenkins-Build ausgeführt werden können. Greift beispielsweise eine Methode auf einen Web-Service oder eine lokale Datenbank zu, kann der Test nicht ausgeführt werden. Man kann dann Mock-Implementierungen der Service-Klasse bzw. der Persistenz-Schicht erzeugen und mit diesen als Ersatz den Unit-Test durchführen.

So tun als gäbe es: Der Typ eines Parameters der zu testenden Methode sei ein Interface. Dann benötigt man für den Aufruf der Methode im Rahmen des Unit-Tests eine Objekt-Instanz einer Klasse die das Interface implementiert. Statt das Interface selbst zu implementieren, überläßt man Mockito die Fußarbeit und nutzt einen Mock.

Prüfen, ob: In vielen Unit-Tests möchte man sicherstellen, daß beim Durchlauf eine bestimmte Methode aufgerufen wird (oder garantiert nicht aufgerufen wird) oder daß eine Methode mit bestimmten Argumenten aufgerufen wird. Das läßt sich bei allen Mockito-Mocks serienmäßig überprüfen, Mockito erlaubt es aber auch, "echte" Objekte mit einem Spy-Objekt zu umwickeln über das die entsprechende Information abgerufen werden kann.

Abgrenzung

Anstelle von Mockito-Mocks kann man auch einfach Interfaces implementieren und Klassen ableiten um zu Mock-Implementierungen zu kommen. Java-Interfaces wurden ja auch zu dem Zweck geschaffen, unterschiedlicher Implementierungen mit der gleichen Schnittstelle zu schaffen – warum also Mockito nutzen? Die Erzeugung eines Mockito-Mocks nimmt eine Zeile Code in Anspruch; gleichgültig wieviele Methoden implementiert oder überschrieben werden. Eine konkrete Klasse braucht eine explizite Implementierung und das wird schnell unübersichtlich. Zudem aktualisiert sich der Mock automatisch, weil er erst zur Laufzeit entsteht. Eine händische Implementierung eines Interface muß jedesmal angefaßt werden, wenn sich das Interface ändert – ein Mockito-Mock nicht.

Zum Schluß der Einleitung sei darauf hingewiesen, was Mockito nicht mocken kann:

  • statische Methoden
  • private Methoden
  • finale Klassen und Methoden

Auf dieser Seite geht es um die Erstellung von Mocks. Spies und alternative Vorgehen werden hier behandelt, um das Überprüfen des Aufrufverhaltens hier.

Mocking

Mocking hat zwei Schritte. Zunächst wird ein Mock-Objekt von der gewünschten Klasse erzeugt, dann werden Methoden des Objekts in der Weise implementiert wie es für den Test erforderlich ist.

Der zweite Schritt ist optional, ein vollständig funktionsloser Mock ist in vielen Fällen schon ausreichend. In aller Regel wird man dem Mock jedoch Funktionalität hinzufügen wollen. Diese Einführung folgt diesem Vorgehen und beschreibt die nötigen Werkzeuge. Alternative Ansätze werden hier besprochen.

Das Mock-Objekt

Der einfachste Mock für ein Objekte einer Klasse oder eines Interfaces erlaubt den Aufruf jeder nicht-statischen, non-private, non-final Methode ohne daß dabei eine Exception auftritt. Er wird so erzeugt:

Foo mock = Mockito.mock(Foo.class);

Die Methoden des Mocks tun nichts, sie rufen auch keine super-Methoden auf. Es wird nur sichergestellt daß jede Methode gefahrlos aufgerufen werden kann und ggf. einen gültigen, wenn auch bedeutungslosen Wert liefert. Anstelle von Objekten (dazu gehören auch Strings) erhält man stets null, numerische Ergebnisse sind immer 0 und boolean-Methoden liefern immer false.

Wird eine Klasse gemockt, erzeugt Mockito eine Ableitung der zu mockenden Klasse. In der Folge können weder finale Klassen noch finale Methoden gemockt werden. Gleiches gilt für statische Methoden, die nicht vererbt werden.

Der Mock kann auf Felder der gemockten Klasse zugreifen, solange diese nicht private sind. Allerdings kann er keine eigenen Felder definieren. Auf public und package visible Felder kann auch von außen zugegriffen werden.

Mocken von Methoden

Wie erwähnt, liefern Methoden gemockter Klassen nur default-Werte; das ist selten ausreichend. Betrachten wir zunächst die einfachste Variante: bei jedem Aufruf der Methode solleb die gleichen, feste Werte geliefert werden. Wir mocken dafür das folgende Interface:

public interface Person {
    String id();
    String abteilung();
    int foo(String dings);
}

Parameterlose Methoden

Soll etwa die ID der Person immer den Wert 5 liefern, könnte das so aussehen:

person = Mockito.mock(Person.class);
Mockito.when(person.id()).thenReturn(5);

Das Argument der when-Methode ist ein Methoden-Aufruf auf den Mock, das Argument der thenReturn-Methode ist der zu liefernde Wert. Soll die Methode eine Abfolge fester Werte liefern, kann man eine Liste angeben:

Mockito.when(person.abteilung()).thenReturn("BLA", "FOO");

Beim ersten Aufruf liefert die Methode den String BLA und beim zweiten FOO. Man kann die Werte auch einzeln angeben:

Mockito.when(person.abteilung())
    .thenReturn("BLA")
    .thenReturn("FOO");

Verwendet man die zweite Variante, kann man die gemockte Methode auch dazu bringen, zwischendurch Exceptions zu werfen:

Mockito.when(person.abteilung())
    .thenReturn("BLA")
    .thenThrow(new RuntimeException());
    .thenReturn("FOO");

Sind alle Werte durch Aufruf verbraucht, liefert die Methode wieder den default-Wert.

Methoden mit Parametern

Die meisten Methoden haben einen oder mehrere Parameter. Will man solche Methoden mocken, muß man spezifizieren bei welchen Argumenten welche Ergebnisse geliefert werden sollen. Im einfachsten Falle gibt man den Argument-Wert als Literal vor:

Foo p = Mockito.mock(Person.class);
Mockito.when(p.foo("x")).thenReturn(10);
Assertions.assertThat(p.foo("x")).isEqualTo(10);

Die Methode foo liefert für foo("X") nun den Wert 10 und für alle anderen Argumente einen undefinierten Wert. Wie erwähnt wird die Methode für alle anderen Argumente den Wert 0 liefern, aber man sollte sich nicht darauf verlassen, daß das auch immer und unter allen Umständen so sein wird.

In den meisten Fällen wird man nicht auf einzelne Werte reagieren wollen, sondern auf Gruppen von Werten oder auf alle möglichen Werte. Um das zu bewerkstelligen werden Matcher benötigt, die beim Aufruf versuchen die Argumente zu matchen. Die Mockito-Matcher werden über statische Methoden der Klasse ArgumentMatchers bereitgestellt.

Da unsere Einstiegsklasse Mockito davon ableitet, "erbt" sie alle dort beheimateten statischen Methodem. Der Kürze halber wird man sie also –- wie hier dargestellt –- über die Mockito-Klasse referenzieren. Das ist nach der reinen Java-Lehre eigentlich nicht sauber, da statische Methoden nicht vererbbar sind. Aber da hier keine Probleme zu erwaretn sind, darf der Test-Code sich das erlauben.

Im Folgenden werden einige häufig benutzte Matcher vorgestellt.

Immer das Gleiche

Um für jedes beliebige Argument den gleichen Wert zuliefern, verwendet man einen der vielen any-Matcher. Mockito.anyString() etwa akzeptiert jeden String mit Ausnahme von null -- dazu später:

Mockito.when(p.foo(Mockito.anyString())).thenReturn(12);

Die Methode foo liefert nun für jedes beliebige String-Argument – ganz verläßlich – den Wert 12. Analog zu String bietet Mockito für eine Vielzahl von Typen – darunter auch für alle simplen Typen wie int oder boolean – Matcher an, die jeweils mit "any" beginnen. Kann der Compiler den Typ selbst erkennen, geht auch das generische any():

Mockito.when(p.foo(Mockito.any())).thenReturn(10);

Handelt es sich um eine Klasse, kann man den Typ auch explizit angeben:

Mockito.when(p.foo(Mockito.any(String.class))).thenReturn(10);

Soll neben echten Objekten auch null als Argument akzeptiert werden, verwendet man nullable; das geht nur unter Angabe einer Klasse:

Mockito.when(p.foo(Mockito.nullabe(String.class))).thenReturn(10);

Möchte man nur auf null reagieren geht das auch, diesmal ohne Klasse:

Mockito.when(p.foo(Mockito.isNull())).thenReturn(10);

Manchmal das Gleiche

Das Konstrukt Mockito.anyString() liefert einen Matcher. Das ist ein Objekt, das beim Aufruf den Eingabe-Wert analysiert und Übereinstimmungen signalisiert. Erkennt der Matcher im when()-Teil das definierte Muster, wird der Wert des thenReturn() als Ergebnis geliefert.

Neben den any-Matchern giebt es eine Fülle anderer Matcher die auf verschiedene Auswahlen von Argumenten passen. Zum Gebrauch sei auf die API-Doku von ArgumentMatchers verwiesen.

Die meisten Fälle lassen sich aber mit dem Universal-Matcher argThat behandeln. Er verlangt als Argument eine Implementierung des (funktionalen) Interfaces ArgumentMatcher <T> (ohne -s!). Das Interface ist äquivalent zum JDK-Interface Predicate, es hat einen Objekt-Parameter und liefert true für "Match" oder false oder "kein Match". Dadurch läßt sich jeder passende λ-Ausdruck als Matcher verwenden. In voller λ-Geschwätzigkeit sieht das zum Beispiel so aus:

Mockito.when(p.foo(ArgumentMatchers.argThat((String s) -> s.length() > 5))).thenReturn(10);

Wenn das das alles nicht reicht, findet man in der hamcrest-Bibliothek eine unglaubliche Fülle weiterer Matcher.

Mal dies -- mal das

Man kann beliebig viele .when-Konstrukte verwenden um den Mock für unterschiedlichen Argumente unterschiedliche Ergebnisse liefern zu lassen. Mockito wendet die Matcher bei der späteren Ausführung in der umgekehrten Reihenfolge ihrer Definition an. In der folgenden Kombination

Foo p = Mockito.mock(Foo.class);
Mockito.when(p.foo(Mockito.anyString())).thenReturn(12);
Mockito.when(p.foo("x")).thenReturn(10);

liefert foo("x") daher den Wert 10 und für jedes andere Argument liefert foo den Wert 12. Selbstverständlich lassen sich in jedem Ausdruck beliebige Matcher verwenden. Man muß bei der Definition aber darauf achten, daß die allgemeineren Matcher zuerst kommen. Fügt man dem letzten Beispiel etwa noch ein .when mit einem anyString() an:

Mockito.when(Mockito.anyString()).thenReturn(4711);

dann werden alle vorher definierten Regeln ignoriert weil die letzte und allgemeinste Regel zuerst zieht.

Methoden responsive mocken

Die oben vorgestellten Verfahren liefern bei jedem Methoden-Aufruf feste Werte die bei der Mock-Definition festgelegt werden. Oft ist es aber erforderlich, daß bei Aufruf der gemockten Methode Werte zurückgeliefert die aus den Argumenten errechnet werden. Oder es ist erforderlich, daß die gemockte Methode irgendwelche Aktivitäten ausführt.

Mit den genannten Verfahren ist das nicht möglich, man benötigt eine "Answer". Dazu stehen zwei Varianten zur Verfügung die sich in der Reihenfolge der Definition unterscheiden. Welche Variante man bevorzugt ist in vielen Fällen unerheblich, when ... thenAnswer ist vielleicht etwas "intuitiver". Keine Wahl hat man, wenn man eine void-Methode mocken möchte. Auch beim Mocken einzelner Methoden eines Spys muß man die zweite Variante verwenden. Als Beispiel sei für das Interface

public interface Transform {
    String calc(int value);
}

ein Mock definiert durch:

Transform trans = Mockito.mock(Transform.class);

Um das Verhalten der Methode calc zu definieren bauen wir ein Objekt vom Typ Answer<T>. Der Typ T wird ersetzt durch den Ergebnis-Typ der zu mockenden Methode -- in diesem Falle String.

Das Answer<T>-Objekt muß eine Methode überschreiben die ein Objekt der Klasse InvocationOnMock als Argument nimmt. Über dieses Objekt erhalten wir Informtionen zu den Argumenten beim Aufruf der Mock-Methode. Wir können sie mit der Methode getArgument über ihren Index abrufen, der Index beginnt bei 0. Für die weiteren Methoden der Klasse sei auf die API-Dokumentation verwiesen.

Betrachten wir dazu eine konkrete Implementierung.

when ... thenAnswer

Die erste Variante nennt erst den Mock und dann die zu mockende Methode:

Mockito.when(trans.calc(Mockito.anyString())).thenAnswer(new Answer<String>() {
    @Override
    public String answer(InvocationOnMock invocation) throws Throwable {
        Integer value = invocation.getArgument(0);
        return value.toString();
    }
});

Mit Java-8 läßt sich die anonyme Klasse auch eleganter mit einem λ-Ausdruck schreiben:

Mockito.when(trans.calc(Mockito.anyString())).thenAnswer(
   (Answer<String>) invocation -> {
       Integer value = invocation.getArgument(0);
       return value.toUpperCase();
   }
);

Der Ergebnis-Typ von getArgument wird hier durch die Variable bestimmt der das Ergebnis zugewiesen wird. Ob die Argument-Typen tatsächlich übereinstimmen, kann Java zur Compile-Zeit leider nicht kontrollieren. Der Entwickler muß also selber darauf achten, daß alle Typen korrekt angegeben werden.

Im Gegensatz zur anonymen-Klasse-Variante kann im λ-Ausdruck der Ergebnis-Typ Answer<String> weggelassen werden. Man sollte ihn aber trotzdem hinschreiben, damit der Typ dokumentiert ist – man tut sich damit bei der Fehlersuche erheblich leichter.

In den obigen Beispielen werden die Argumente vor Gebrauch in lokale Variablen abgefüllt, bevor diese im return-Ausdruck verwendet werden. Das ist in der Regel nicht erforderlich, man kann die Typen von der Java-Magie bestimmern lassen. Die geschwätzige Variante mit den lokalen Variablen hat aber den Vorteil, daß die Typen auf den ersten Blick zu erkennen sind. Werden schrecklich Methoden mit vielen Parametern aufgerufen, wird das schnell zum Geduldspiel.

doAnswer ... when

Bei dieser Variante wird erst die Answer definiert und hinterher der Mock und die aufzurufende Methode. Auch hier gewinnt der Aufruf durch die Verwendung von λ-Ausdrücken durchaus an Lesbarkeit -- wir lassen die konventionelle Variante diesmal weg:

Mockito.doAnswer(
    (Answer<String>) invocation -> {
        Integer value = invocation.getArgument(0);
        return value.toString();
    }
).when(trans.calc(Mockito.anyString()));

Das Konstrukt funktioniert genauso wie das im vorangegangenen Abschnitt beschrieben.

Allerdings kann man den Aufruf auch subtil anders gestalten (hier wird nur die λ-Variante wiedergegeben):

Mockito.doAnswer(
    (Answer<String>) invocation -> {
        Integer value = invocation.getArgument(0);
        return value.toString();
    }
).when(trans).calc(Mockito.anyString());

Der Unterschied liegt in der letzten Zeile. Im ersten Falle wird .when() mit dem Mock der gemockten Methode aufgerufen. Im zweiten Falle wird .when() mit dem Mock der gemockten Klasse aufgerufen. Die zweite Variante macht das Mocking von void-Methoden möglich und erlaubt, einzelne Methoden von Spy-Objekten zu mocken und damit partielle Mocks zu erzeugen.

void-Methoden: Methoden ohne Ergebnis

Eine void-Methode ist eine Methode, die kein Ergebnis liefert – was sollte man hier mocken? Betrachten wir dazu folgendes Beispiel:

public class CustomerManager {
    public void save(Customer customer) {
        getDatabaseLink().merge(customer);
    }
}

Die save-Methode nimmt als Parameter ein Entity und persistiert dessen Inhalt in der Datenbank. Das ist etwas, was wir im Unit-Test normalerweise nicht tun möchten. Wir würden stattdessen den vielleicht den Aufruf protokollieren oder die Persistierung in einem Java-Objekt emulieren.

Beim Mocking geht es also darum, beim Ausführen der gemockten void-Methode einen Seiteneffekt herbeizuführen. Wie bereits beschrieben, giebt es prinzipiell zwei Muster nach denen sich in Mockito Methoden-Verhalten implementieren läßt. Im Falle von void-Methoden fällt das when...then-Pattern jedoch aus, da die Methode Mockito.when() keine void-Methoden verdauen kann.

Wir erzeugen also erstmal einen Mock:

Transform mock = Mockito.mock(CustomerManager.class);

und definieren die Antwort so:

Mockito.doAnswer(new Answer<Void>() {
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        // Seiteneffekt
        return null;
    }
}).when(mock).save(Mockito.any(Customer.class));

Der Trick ist die Verwendung der – übrigens schon seit JDK 1.1 existierenden – Klasse Void(mit großem Vau). Zu jedem primitiven Typ gibt es in Java eine passende Wrapper-Klasse; ein Analogon hat der Ergebnis-Typ void in der Void-Klasse. Da es keine void-Werte giebt, giebt es auch keine Instanzen der Void-Klasse; die Klasse selbst gibt es aber und hier finden wir eine Gelegenheit sie zu nutzen: wir definieren damit den Ergebnis-Typ der Answer-Methode.

Da Void – im Gegensatz zu void – eine Klasse ist, muß die answer-Methode ein Ergebnis liefern und benötigt daher am Ende die Anweisung return null.

Natürlich läßt sich das auch mit einem λ-Ausdruck schreiben:

Mockito.doAnswer((Answer<Void>) invocation -> {
    // Seiteneffekt
    return null;
}).when(mock).save(Mockito.any(Customer .class));

Methoden mit Variablen Argument-Listen

Weichen wir mal der Diskussion aus, ob Var-Arg-Methoden schön, sinnvoll oder wünschenswert sind und welche Probleme sie mit sich bringen (könnten). Nehmen wir einfach an, wir hätten so ein Ding und müßten es mocken -- wie geht das? Die Methode process akzeptiere eine beliebige Anzahl von Customer-Objekten, tue irgendwas damit und liefere die Anzahl der verarbeiteten Objekte.

public interface Transform {
    int process(Customer... customer);
}

Wie bereits beschrieben, können wir über ein Objekt der Klasse InvocationOnMock auf die Argumente zugreifen die beim Aufruf der gemockten Methode übergeben werden. Die vararg-Argumente erhalten wir so als array und können z.B. mit einer for-Schleife darüber iterieren. Versuchen wir es hier etwas hübscher aussehen zu lassen, indem wir das array in eine typisierte Liste überführen.

Wir schreiben zunächst die Mock-Methode mit dem doAnswer...when-Pattern:

void test() {
    Mockito.doAnswer(new Answer<Integer>() {
        @Override
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            List<Customer> kunden = argliste(invocation.getArguments());
            return kunden.size();
        }
    }).when(mock).process(Mockito.any());
}

Und nun zur .argliste()-Methode, die das Object-array in ein List<Customer>-Objekt umwandelt. Es giebt viele Möglichkeiten, die elegantesten arbeitet natürlich mit einem Stream. Das Delikate daran ist das erforderliche Casting, wir verwenden dazu die .class-Klasse für die Customer-Klasse:

List<Customer> argliste(Object liste[]) {
    return Stream.of(liste)
        .filter(Customer.class::isInstance)
        .map(Customer.class::cast)
        .collect(Collectors.toList());
}

Was hierbei nicht offensichtlich ist, ist daß die arguments-Methode von InvocationOnMock alle Argumente liefert –- nicht nur die vararg-Argumente. Im folgenden Beispiel int process(String beschreibung, Customer... customer); liefert .arguments()[0] das Argument für den String-Parameter und erst ab .arguments()[1] kommen die vararg-Argumente. Die obige Methode argliste funktioniert auch in diesem Falle unmittelbar, weil der nicht-variable Teil der ParameterListe keine Customer-Objekte enthält. Das String-Argument wird einfach herausgefiltert. Anders sieht es in diesem Beispiel aus:

int process(Customer referenz, String beschreibung, Customer... customer);

Offensichtlich soll das erste Customer-Objekt anders behandelt werden als die der vararg-Liste. Aber auch das geht mit Streams ganz einfach. Wir müssen ja nur die ersten beiden Argumente bei der Verarbeitung überspringen; das geht mit der .skip()-Methode:

List<Customer> argliste(Object liste[]) {
    return Stream.of(liste)
        .skip(2)
        .filter(Customer.class::isInstance)
        .map(Customer.class::cast)
        .collect(Collectors.toList());
}

Und wenn wir die Methode noch öfter brauchen, können wir den start-Index (beginnend bei 0) und das verwendete Class-Objekt noch parametrisieren:

<T> List<T> argliste(Object liste[], int startIndex, Class<T> klasse) {
    return Stream.of(liste)
        .skip(startIndex)
        .filter(klasse::isInstance)
        .map(klasse::cast)
        .collect(Collectors.toList());
}

Diese letzte Variante können wir nun für das Mocking jeder Varag-Methode für jeden Varag-Typ verwenden.

Abstrakte Klassen mocken

Der gemeine Mockito-Mock ersetzt alle Methoden der gemockten Klasse durch leere Mock-Aufrufe die – defaultmäßig – gar nichts tun. Das kann man verhindern durch Angabe eines zusätzlichen Parameters:

MeineKlasse meinMock = mock(MeineKlasse.class, Mockito.CALLS_REAL_METHODS);

Wird jetzt eine Methode des Mocks aufgerufen, ruft dieser die originale Methode der Klasse MeineKlasse auf. Anschließend kann man einzelne Methoden mocken und so einen partiellen Mock zu erzeugen. Bei abstrakten Klassen tritt der Mock in's leere, sobald eine abstrakte Methode aufgerufen wird, weil es für diese naturgemäß keine "echte" Methode giebt, die aufgerufen werden könnte. Um eine abstrakte Klasse so zu mocken, daß genau die abstrakten Methoden gemockt werden, muß man also jede abstrakte Methode durch eine mock-Methode ersetzen – wie öde... Mit der folgenden Klasse kann man das – Reflection sei dank – vollautomatisch erledigen lassen:

import java.lang.reflect.Modifier;
...
public class MockerForAbstractMethods implements Answer<Object> {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        if (Modifier.isAbstract(invocation.getMethod().getModifiers())) {
            return Mockito.RETURNS_DEFAULTS.answer(invocation);
        }
        return Mockito.CALLS_REAL_METHODS.answer(invocation);
    }
}

Diese Klasse legt man an geeigneter Stelle ab, irgendwo im test-Ordner des Projekts. Die Anwendung im Unit-Tests sieht dann so aus:

MeineKlasse meinMock = mock(MeineKlasse.class, new MockerForAbstractMethods());

Das Objekt prüft bei jedem Aufruf ob da eine abstrakte Methode aufgerufen wird und ersetzt den Aufruf durch einen Mock-Aufruf. Ist die Methode nicht abstrakt, wird die "echte" Methode aufgerufen. Um das ganze in der Anwendung etwas gefälliger zu machen, kann man die Instanz statisch erzeugen und eine Konstante dafür definieren:

public static final Answer<Object> MOCK_ABSTRACT_METHODS = new MockerForAbstractMethod();

Die Konstante kann man statisch importieren und dann schreiben:

MeineKlasse meinMock = mock(MeineKlasse.class, MOCK_ABSTRACT_METHODS);