Mockito: Methoden die Class-Objekte liefern

Aus MimiPedia

Mocken von Methoden die Class-Objekte liefern

Ein spezielles Problem ist das mocken von Methoden die Class-Objekte liefern. Betrachten wir dazu folgende Klasse:

class Foo {
    Class<?> klasse() {
        return String.class;
    }
}

Das Mocken der Methode klasse könnte dann so aussehen:

Mockito.when(foo.klasse()).thenReturn(Integer.class);

Läuft aber auf einen Fehler. Auf die Fehler-Ursache kommen wir später zurück, erstmal sehen was sich tun läßt. Es giebt mindestens drei work arounds.

Der Fehler mit dem uns der Compiler konfrontiert sieht so aus:

The method thenReturn(Class<capture#3-of ?>) in the type OngoingStubbing<Class<capture#3-of ?>> is not  
applicable for the arguments (Class<Integer>)

Den return-Wert casten

Der naheligende Versuch, Den Paraneter von Integer.class auf Class<?> zu casten um den Return-Wert des Mocks mit der gemockten Methode in Deckung zu bringen fruchtet nicht -- wo also hincasten? Das Problem hat anscheinend etwas mit der Parametrisierung des Typs der Klasse Class, verwendet man stattdessen den raw type funktionierts:

Mockito.when(foo.klasse()).thenReturn((Class) Integer.class);

Allerdings warnt der Compiler dann vor der Verwendung des raw types. Wen das nicht anficht, der kann's so machen.

Die when-Methode parametrisieren

Schaut man sich die when-Methode genauer an findet man diese Signatur:

public static <T> OngoingStubbing<T> when(T methodCall)

Unsere bisherigen Ansätze haben den Typ-Parameter ignoriert und dem Compiler überlassen herauszufinden wie das T hier zu interpretieren ist. Helfen wir dem Compiler auf die Sprünge und geben den Typ -- es handelt sich um den Return-Typ der gemockten Methode -- explizit an:

Mockito.<Class<?>>when(foo.klasse()).thenReturn(Integer.class);

und schon geht's

doReturn...when

Eine weitere elegante Methode führt über die Umgehung des when...then-Konstrukts. Ohne lange Vorrede:

Mockito.doReturn(Integer.class).when(foo).klasse();

Dieses Konstrukt vermeidet auch die Compiler-Warnung.

Zur Ursache

Das Problem liegt augenscheinlich am Unvermögen des Compilers den richtigen Typ für den Typ-Parameter zu ermitteln. Zumindest schafft der Compiler es nicht die Typen Class<?> und Class zur Deckung zu bringen. Die when-Methode haben wir oben schon gesehen, wie sieht das beim doReturn aus?

public static Stubber doReturn(Object toBeReturned)

Der Typ des Arguments Integer.class das an doReturn übergeben wird, wird irrelevant durch den Parameter-Typ Object und an Stubber nicht weitergegeben. Die Methode when der Interface Stubber ist so definiert:

<T> T when(T mock);

Hier interessiert der Rückgabe-Typ der gemockten Methode überhaupt nicht mehr, T bezeichnet nämlich den Typ des Mocks. Beim doReturn...when-Konstrukt taucht das Problem daher nicht auf.