Gibt es eine Möglichkeit, eine Liste eines bestimmten Typs mit mockitos ArgumentCaptore zu erfassen. Dies funktioniert nicht:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
Gibt es eine Möglichkeit, eine Liste eines bestimmten Typs mit mockitos ArgumentCaptore zu erfassen. Dies funktioniert nicht:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
Das verschachtelte Generika-Problem kann mit dem @Captor-Anmerkung :
public class Test{
@Mock
private Service service;
@Captor
private ArgumentCaptor<ArrayList<SomeType>> captor;
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldDoStuffWithListValues() {
//...
verify(service).doStuff(captor.capture()));
}
}
Ich bevorzuge die Verwendung von MockitoAnnotations.initMocks(this)
im @Before
Methode, anstatt einen Läufer zu verwenden, der die Möglichkeit ausschließt, einen anderen Läufer zu verwenden. Aber +1, danke für den Hinweis auf die Anmerkung.
Ich bin nicht sicher, ob dieses Beispiel vollständig ist. Ich erhalte... Error:(240, 40) java: variable captor might not have been initialized ich mag tenshi's Antwort unten
Ich hatte das gleiche Problem und fand diesen Blogbeitrag, der mir ein wenig geholfen hat: blog.jdriven.com/2012/10/ . Es enthält einen Schritt zur Verwendung von MockitoAnnotations.initMocks, nachdem Sie die Annotation in Ihrer Klasse platziert haben. Eine Sache, die mir aufgefallen ist, ist, dass man sie nicht innerhalb einer lokalen Variable haben kann.
Ja, dies ist ein allgemeines generisches Problem, nicht mockito-spezifisch.
Es gibt kein Klassenobjekt für ArrayList<SomeType>
und daher kann man ein solches Objekt nicht typsicher an eine Methode übergeben, die eine Class<ArrayList<SomeType>>
.
Sie können das Objekt in den richtigen Typ umwandeln:
Class<ArrayList<SomeType>> listClass =
(Class<ArrayList<SomeType>>)(Class)ArrayList.class;
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(listClass);
Dies wird einige Warnungen über unsichere Casts ausgeben, und natürlich kann Ihr ArgumentCaptor nicht wirklich unterscheiden zwischen ArrayList<SomeType>
y ArrayList<AnotherType>
ohne vielleicht die Elemente zu inspizieren.
(Wie in der anderen Antwort erwähnt, ist dies zwar ein allgemeines Generika-Problem, aber es gibt eine Mockito-spezifische Lösung für das Problem der Typsicherheit mit der @Captor
Bemerkung. Es kann immer noch nicht unterscheiden zwischen einer ArrayList<SomeType>
und ein ArrayList<OtherType>
.)
Werfen Sie auch einen Blick auf tenshi Kommentar. Sie können den ursprünglichen Code durch diese vereinfachte Version ersetzen:
final ArgumentCaptor<List<SomeType>> listCaptor
= ArgumentCaptor.forClass((Class) List.class);
Das von Ihnen gezeigte Beispiel kann vereinfacht werden, da Java für die statischen Methodenaufrufe eine Typinferenz vornimmt: ArgumentCaptor<List<SimeType>> argument = ArgumentCaptor.forClass((Class) List.class);
Zum Deaktivieren der unkontrollierte oder unsichere Operationen verwendet Warnung, verwenden Sie die @SuppressWarnings("unchecked")
oberhalb der Zeile für die Definition des Argument-Captors. Auch das Casting nach Class
ist überflüssig.
Wenn Sie keine Angst vor alten Java-Stil (nicht Typ sicher generische) Semantik, dies funktioniert auch und ist simple'ish:
ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
verify(subject).method(argument.capture()); // run your code
List<SomeType> list = argument.getValue(); // first captured List, etc.
List<String> mockedList = mock(List.class);
List<String> l = new ArrayList();
l.add("someElement");
mockedList.addAll(l);
ArgumentCaptor<List> argumentCaptor = ArgumentCaptor.forClass(List.class);
verify(mockedList).addAll(argumentCaptor.capture());
List<String> capturedArgument = argumentCaptor.<List<String>>getValue();
assertThat(capturedArgument, hasItem("someElement"));
Basierend auf den Kommentaren von @tenshi und @pkalinow (auch ein Lob an @rogerdpack), ist die folgende einfache Lösung für die Erstellung eines Listenargument-Captors, der auch die "verwendet ungeprüfte oder unsichere Operationen" Warnung:
@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
ArgumentCaptor.forClass(List.class);
Vollständiges Beispiel ici und den entsprechenden erfolgreichen CI-Build und Testlauf ici .
Unser Team verwendet dies schon seit einiger Zeit in unseren Unit-Tests, und es scheint die einfachste Lösung für uns zu sein.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
10 Stimmen
Ich finde, dass es eine schreckliche Idee ist, hier eine konkrete Listenimplementierung zu verwenden (
ArrayList
). Sie können jederzeit dieList
Schnittstelle, und wenn Sie die Tatsache darstellen wollen, dass sie kovariant ist, dann können Sieextends
:ArgumentCaptor<? extends List<SomeType>>