it-swarm.com.de

So erfassen Sie eine Liste eines bestimmten Typs mit Mockito

Gibt es eine Möglichkeit, eine Liste eines bestimmten Typs mithilfe des ArgumentCaptor zu erfassen. Das funktioniert nicht:

ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
236

Das geschachtelte Generics-Problem kann mit der Annotation @Captor vermieden werden:

@RunWith(MockitoJUnitRunner.class)
public class Test{

    @Mock
    private Service service;

    @Captor
    private ArgumentCaptor<ArrayList<SomeType>> captor;

    @Test 
    public void shouldDoStuffWithListValues() {
        //...
        verify(service).doStuff(captor.capture()));
    }
}
430
crunchdog

Ja, das ist ein generisches Problem, nicht Mockito-spezifisch.

Es gibt kein Klassenobjekt für ArrayList<SomeType>. Daher können Sie ein solches Objekt nicht typsicher an eine Methode übergeben, die einen Class<ArrayList<SomeType>> erfordert.

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);

Dadurch werden einige Warnungen zu unsicheren Besetzungen ausgegeben. Natürlich kann Ihr ArgumentCaptor nicht wirklich zwischen ArrayList<SomeType> und ArrayList<AnotherType> unterscheiden, ohne die Elemente zu prüfen.

(Wie in der anderen Antwort erwähnt, gibt es zwar eine generische Problematik für Generika, es gibt jedoch eine Mockito-spezifische Lösung für das Typsicherheitsproblem mit der Annotation @Captor. Es kann immer noch nicht zwischen ArrayList<SomeType> und ArrayList<OtherType> unterschieden werden.)

Bearbeiten:

Schau dir auch den Kommentar von tenshi s an. Sie können den Originalcode von Paŭlo Ebermann ändern (viel einfacher).

final ArgumentCaptor<List<SomeType>> listCaptor
        = ArgumentCaptor.forClass((Class) List.class);
114
Paŭlo Ebermann

Wenn Sie keine Angst vor alter Java-artiger (nicht typsicherer generischer) Semantik haben, funktioniert dies auch und ist ziemlich einfach:

ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
verify(subject.method(argument.capture()); // run your code
List<SomeType> list = argument.getValue(); // first captured List, etc.
12
rogerdpack
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"));
6
kkmike999

Basierend auf den Kommentaren von @ tenshi und @ pkalinow (auch kudos an @rogerdpack), ist das Folgende eine einfache Lösung zum Erstellen eines Listenargument-Captors, der die Warnung deaktiviert, dass "ungeprüfte oder unsichere Operationen verwendet":

@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
    ArgumentCaptor.forClass(List.class);

Vollständiges Beispiel hier und entsprechende übergebene CI-Erstellung und Testlauf hier .

Unser Team hat dies schon seit geraumer Zeit in unseren Unit-Tests eingesetzt, und dies scheint für uns die einfachste Lösung zu sein.

2
mrts

Für eine frühere Version von junit können Sie dies tun

Class<Map<String, String>> mapClass = (Class) Map.class;
ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(mapClass);
1
quzhi65222714

Ich hatte das gleiche Problem mit der Testaktivität in meiner Android-App. Ich habe ActivityInstrumentationTestCase2 verwendet und MockitoAnnotations.initMocks(this); hat nicht funktioniert ..__ Ich habe dieses Problem mit einer anderen Klasse mit entsprechendem Feld gelöst. Zum Beispiel:

class CaptorHolder {

        @Captor
        ArgumentCaptor<Callback<AuthResponse>> captor;

        public CaptorHolder() {
            MockitoAnnotations.initMocks(this);
        }
    }

Dann in der Aktivitätstestmethode:

HubstaffService hubstaffService = mock(HubstaffService.class);
fragment.setHubstaffService(hubstaffService);

CaptorHolder captorHolder = new CaptorHolder();
ArgumentCaptor<Callback<AuthResponse>> captor = captorHolder.captor;

onView(withId(R.id.signInBtn))
        .perform(click());

verify(hubstaffService).authorize(anyString(), anyString(), captor.capture());
Callback<AuthResponse> callback = captor.getValue();
0