Mockito: Methoden die Class-Objekte liefern: Unterschied zwischen den Versionen

Aus MimiPedia
(Die Seite wurde neu angelegt: „= Mocken von Methoden die Class-Objekte liefern = Ein spezielles Problem ist das mocken von Methoden die {{java|Class}}-Objekte liefern. Betrachten wir dazu fo…“)
 
Keine Bearbeitungszusammenfassung
 
(Eine dazwischenliegende Version desselben Benutzers wird nicht angezeigt)
Zeile 1: Zeile 1:
[[Category:Java]]
[[Category:Mockito]]
= Mocken von Methoden die Class-Objekte liefern =
= Mocken von Methoden die Class-Objekte liefern =
Ein spezielles Problem ist das mocken von Methoden die {{java|Class}}-Objekte liefern.
Ein spezielles Problem ist das mocken von Methoden die {{java|Class}}-Objekte liefern.
Zeile 13: Zeile 15:
Mockito.when(foo.klasse()).thenReturn(Integer.class);
Mockito.when(foo.klasse()).thenReturn(Integer.class);
}}
}}
Läuft aber auf einen Fehler. Was den Fehler tatsächlich verursacht ist noch zu untersuchen, jedenfalls geht's so nicht -- aber wie dann? Es giebt dafür mindestens zwei work arounds:
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.


== Casting ==
Der Fehler mit dem uns der Compiler konfrontiert sieht so aus:
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   
  The method thenReturn(Class<capture#3-of ?>) in the type OngoingStubbing<Class<capture#3-of ?>> is not   
  applicable for the arguments (Class<Integer>)
  applicable for the arguments (Class<Integer>)


Was hingegen nicht funktioniert ist ein Casting von {{java|Integer.class}} auf {{java|Class<?>}}.
== Den return-Wert casten ==
Wo also hincasten? Das Problem hat anscheinend etwas mit der Parametrisierung des Typs der Klasse {{java|Class}}, verwendet man stattdessen den raw type funktionierts:
Der naheligende Versuch, Den Paraneter von {{java|Integer.class}} auf {{java|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 {{java|Class}}, verwendet man stattdessen den raw type funktionierts:
{{java|code=
{{java|code=
Mockito.when(foo.klasse()).thenReturn((Class) Integer.class);
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.
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:
{{java|code=
public static <T> OngoingStubbing<T> when(T methodCall)
}}
Unsere bisherigen Ansätze haben den Typ-Parameter ignoriert und dem Compiler überlassen herauszufinden wie das {{java|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:
{{java|code=
Mockito.<Class<?>>when(foo.klasse()).thenReturn(Integer.class);
}}
und schon geht's


== doReturn...when ==
== doReturn...when ==
Die elegantere Methode führt über die Umgehung des when...then-Konstrukts. Ohne lange Vorrede:
Eine weitere elegante Methode führt über die Umgehung des when...then-Konstrukts. Ohne lange Vorrede:
{{java|code=
{{java|code=
Mockito.doReturn(Integer.class).when(foo).klasse();
Mockito.doReturn(Integer.class).when(foo).klasse();
}}
}}
Dieses Konstrukt vermeidet auch die Compiler-Warnung.
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 {{java|Class<?>}} und {{java|Class}} zur Deckung zu bringen. Die {{java|when}}-Methode haben wir oben schon gesehen, wie sieht das beim {{java|doReturn}} aus?
{{java|code=
public static Stubber doReturn(Object toBeReturned)
}}
Der Typ des Arguments {{java|Integer.class}} das an {{java|doReturn}} übergeben wird, wird irrelevant durch den Parameter-Typ {{java|Object}} und an {{java|Stubber}} nicht weitergegeben. Die Methode {{java|when}} der Interface {{java|Stubber}} ist so definiert:
{{java|code=
<T> T when(T mock);
}}
Hier interessiert der Rückgabe-Typ der gemockten Methode überhaupt nicht mehr, {{java|T}} bezeichnet nämlich den Typ des Mocks. Beim doReturn...when-Konstrukt taucht das Problem daher nicht auf.

Aktuelle Version vom 23. Juni 2021, 18:53 Uhr

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.