Verwenden von Mockito zum Nachahmen von Klassen mit generischen Parametern
Lesezeit: 6 Minuten
Gibt es eine saubere Methode, eine Klasse mit generischen Parametern zu verspotten? Angenommen, ich muss eine Klasse verspotten Foo<T> die ich in eine Methode übergeben muss, die a erwartet Foo<Bar>. Folgendes kann ich problemlos tun:
Vorausgesetzt getValue() gibt den generischen Typ zurück T. Aber das wird Kätzchen haben, wenn ich es später in eine Methode erwarte Foo<Bar>. Ist Casting die einzige Möglichkeit, dies zu tun?
Warum foo und bar gegenüber aussagekräftigeren Namen verwenden? Hat gerade bei vielen Leuten eine ganze Menge Verwirrung gestiftet.
– Kaigo
25. Juli 2020 um 20:26 Uhr
@Kaigo Es ist ziemlich üblich, in Programmierbeispielen foo, bar und baz zu verwenden, insbesondere wenn Beispiele aus der realen Welt anonymisiert werden, um vertrauliche Details zu verbergen. Jetzt mache ich mir mehr Sorgen um die Tatsache, dass OP den Ausdruck “das wird Kätzchen haben” verwendet hat … buchstäblich noch nie zuvor jemanden sagen hören;)
– Adam Burley
13. März 2021 um 14:04 Uhr
Jeder weiß, dass “Kätzchen zu haben” eine schlechte Sache für Code ist, auch wenn es für Katzen ziemlich großartig ist. :--)
– Charlie Reitzel
29. Januar um 18:12 Uhr
Johannes Paulett
Ich denke, Sie müssen es werfen, aber es sollte nicht so schlimm sein:
Ja, aber Sie haben immer noch eine Warnung. Kann man die Abmahnung umgehen?
– odwl
31. August 2010 um 19:11 Uhr
@SuppressWarnings(“nicht markiert”)
– qualifiziert
10. Dezember 2010 um 1:13 Uhr
Ich denke, das ist völlig akzeptabel, da wir über ein Scheinobjekt in einem Komponententest sprechen.
– Magnilex
26. November 2014 um 13:06 Uhr
@demaniak Es funktioniert überhaupt nicht. Argument-Matcher können in diesem Kontext nicht verwendet werden.
– Krzysztof Krason
19. Mai 2018 um 20:53 Uhr
@demaniak Das lässt sich gut kompilieren, aber wenn der Test ausgeführt wird, wird InvalidUseOfMatchersException ausgelöst (was eine RuntimeException ist).
– Superole
4. Juni 2018 um 12:32 Uhr
Marek Kirejczyk
Eine andere Möglichkeit, dies zu umgehen, ist die Verwendung @Mock Anmerkung statt. Funktioniert nicht in allen Fällen, sieht aber viel sexier aus 🙂
Hier ist ein Beispiel:
@RunWith(MockitoJUnitRunner.class)
public class FooTests {
@Mock
public Foo<Bar> fooMock;
@Test
public void testFoo() {
when(fooMock.getValue()).thenReturn(new Bar());
}
}
dies ist in 1.9.5 veraltet. 🙁 Scheint mir viel sauberer zu sein.
– Pure Funktion
27. März 2014 um 21:36 Uhr
@CodeNovitiate Ich konnte in 1.9.5 keine Verfallsanmerkungen zu MockitoJUnitRunner und Mock finden. Also, was ist veraltet? (Ja, org.mockito.MockitoAnnotations.Mock ist veraltet, aber Sie sollten stattdessen org.mockito.Mock verwenden)
– neu242
22. Mai 2014 um 7:31 Uhr
Gut gemacht, das hat bei mir perfekt funktioniert. Es ist nicht nur “sexier”, es vermeidet eine Warnung ohne Verwendung SuppressWarnings. Warnungen gibt es aus einem bestimmten Grund, es ist besser, sie nicht zu unterdrücken. Vielen Dank!
– Nicole
3. Juni 2014 um 17:43 Uhr
Es gibt eine Sache, die ich an der Verwendung nicht mag @Mock Anstatt von mock(): Die Felder sind während der Bauzeit immer noch null, daher kann ich zu diesem Zeitpunkt keine Abhängigkeiten einfügen und die Felder nicht endgültig machen. Ersteres kann durch a gelöst werden @Before-kommentierte Methode natürlich.
– Rüdiger Schulz
25. September 2014 um 9:26 Uhr
Rufen Sie zur Initiierung einfach MockitoAnnotations.initMocks(this) auf;
– borjab
6. April 2016 um 12:31 Uhr
Singleton
Sie könnten immer eine Zwischenklasse/Schnittstelle erstellen, die den generischen Typ erfüllt, den Sie angeben möchten. Wenn beispielsweise Foo eine Schnittstelle wäre, könnten Sie die folgende Schnittstelle in Ihrer Testklasse erstellen.
private interface FooBar extends Foo<Bar>
{
}
In Situationen, in denen Foo a nicht endgültig Klasse, Sie könnten die Klasse einfach mit dem folgenden Code erweitern und dasselbe tun:
public class FooBar extends Foo<Bar>
{
}
Dann könnten Sie eines der obigen Beispiele mit dem folgenden Code verwenden:
Bereitgestellt Foo eine Schnittstelle oder nicht-finale Klasse ist, scheint dies eine recht elegante Lösung zu sein. Vielen Dank.
– Tim Clemons
29. April 2014 um 15:39 Uhr
Ich habe die Antwort aktualisiert, um auch Beispiele für nicht endgültige Klassen aufzunehmen. Idealerweise würden Sie gegen eine Schnittstelle codieren, aber das wird nicht immer der Fall sein. Guter Fang!
– Singleton
30. April 2014 um 15:15 Uhr
Ein … kreieren Test-Utility-Methode. Besonders nützlich, wenn Sie es mehr als einmal benötigen.
@Test
public void testMyTest() {
// ...
Foo<Bar> mockFooBar = mockFoo();
when(mockFooBar.getValue).thenReturn(new Bar());
Foo<Baz> mockFooBaz = mockFoo();
when(mockFooBaz.getValue).thenReturn(new Baz());
Foo<Qux> mockFooQux = mockFoo();
when(mockFooQux.getValue).thenReturn(new Qux());
// ...
}
@SuppressWarnings("unchecked") // still needed :( but just once :)
private <T> Foo<T> mockFoo() {
return mock(Foo.class);
}
Ich stimme zu, dass man Warnungen in Klassen oder Methoden nicht unterdrücken sollte, da man andere, versehentlich unterdrückte Warnungen übersehen könnte. Aber IMHO ist es absolut sinnvoll, eine Warnung zu unterdrücken, die nur eine einzige Codezeile betrifft.
Tut mir leid, dass ich diesen Beitrag necro, aber ich habe noch nie Anmerkungen zu einer Aussage wie dieser in Java gesehen, und die Dokumente sag auch nichts dazu. Übersehe ich etwas?
– Rabadash8820
12. August um 16:30 Uhr
Wie in den anderen Antworten erwähnt, gibt es keine gute Möglichkeit, die zu verwenden mock() & spy() Methoden direkt ohne unsicheren Generika-Zugriff und/oder Unterdrückung von Generika-Warnungen.
Es gibt derzeit ein offenes Problem im Mockito-Projekt (#1531), um Unterstützung für die Verwendung von hinzuzufügen mock() & spy() Methoden ohne Generika-Warnungen. Das Problem wurde im November 2018 eröffnet, aber es gibt keine Hinweise darauf, dass es priorisiert wird. Laut einem der Kommentare des Mockito-Mitarbeiters zu diesem Problem:
Angesichts dessen .class nicht gut mit Generika spielt, glaube ich nicht, dass wir in Mockito eine Lösung finden können. Kannst du schon @Mock (Die JUnit5-Erweiterung erlaubt auch Methodenparameter @Mocks) und das sollte eine geeignete Alternative sein. Daher können wir dieses Problem offen halten, aber angesichts dessen ist es unwahrscheinlich, dass es jemals behoben wird @Mock ist eine bessere API.
Tut mir leid, dass ich diesen Beitrag necro, aber ich habe noch nie Anmerkungen zu einer Aussage wie dieser in Java gesehen, und die Dokumente sag auch nichts dazu. Übersehe ich etwas?
– Rabadash8820
12. August um 16:30 Uhr
Vogella
Mit JUnit5 denke ich, dass der beste Weg ist, @ExtendWith(MockitoExtension.class) mit @Mock im Methodenparameter oder im Feld zu verwenden.
Das folgende Beispiel zeigt dies mit Hamcrest-Matchern.
Warum foo und bar gegenüber aussagekräftigeren Namen verwenden? Hat gerade bei vielen Leuten eine ganze Menge Verwirrung gestiftet.
– Kaigo
25. Juli 2020 um 20:26 Uhr
@Kaigo Es ist ziemlich üblich, in Programmierbeispielen foo, bar und baz zu verwenden, insbesondere wenn Beispiele aus der realen Welt anonymisiert werden, um vertrauliche Details zu verbergen. Jetzt mache ich mir mehr Sorgen um die Tatsache, dass OP den Ausdruck “das wird Kätzchen haben” verwendet hat … buchstäblich noch nie zuvor jemanden sagen hören;)
– Adam Burley
13. März 2021 um 14:04 Uhr
Jeder weiß, dass “Kätzchen zu haben” eine schlechte Sache für Code ist, auch wenn es für Katzen ziemlich großartig ist.
:--)
– Charlie Reitzel
29. Januar um 18:12 Uhr