Existe-t-il un moyen de capturer une liste de types spécifiques en utilisant mockito ArgumentCaptor. Cela ne marche pas:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
Le problème générique imbriqué peut être évité avec l'annotation @Captor :
@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()));
}
}
Oui, c’est un problème général lié aux génériques, pas spécifique à Mockito.
Il n'y a pas d'objet de classe pour ArrayList<SomeType>
et vous ne pouvez donc pas le transmettre en toute sécurité à une méthode nécessitant un Class<ArrayList<SomeType>>
.
Vous pouvez convertir l'objet dans le bon type:
Class<ArrayList<SomeType>> listClass =
(Class<ArrayList<SomeType>>)(Class)ArrayList.class;
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(listClass);
Cela donnera des avertissements sur les conversions non sécurisées, et bien sûr, votre ArgumentCaptor ne peut pas vraiment faire la différence entre ArrayList<SomeType>
et ArrayList<AnotherType>
sans peut-être inspecter les éléments.
(Comme mentionné dans l'autre réponse, bien qu'il s'agisse d'un problème générique général, il existe une solution spécifique à Mockito pour le problème de sécurité de type associé à l'annotation @Captor
. Il ne peut toujours pas faire la distinction entre un ArrayList<SomeType>
et un ArrayList<OtherType>
.)
Regardez aussi le commentaire tenshi s. Vous pouvez changer le code original de Paŭlo Ebermann en ceci (beaucoup plus simple)
final ArgumentCaptor<List<SomeType>> listCaptor
= ArgumentCaptor.forClass((Class) List.class);
Si vous n'êtes pas effrayé par les vieilles sémantiques de style Java (générique de type non sécurisé), cela fonctionne aussi et reste relativement simple:
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"));
Sur la base des commentaires de @ tenshi et de @ pkalinow (également félicitations à @rogerdpack), voici une solution simple pour créer un capteur d'arguments de liste qui désactive également le "utilise des opérations non contrôlées ou non sécurisées"
@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
ArgumentCaptor.forClass(List.class);
Exemple complet ici et la construction et le test réussis de l'EC réussi ici .
Notre équipe utilise cela depuis quelque temps dans nos tests unitaires et cela semble être la solution la plus simple pour nous.
Pour une version antérieure de Junit, vous pouvez faire
Class<Map<String, String>> mapClass = (Class) Map.class;
ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(mapClass);
J'ai eu le même problème avec l'activité de test dans mon application Android. J'ai utilisé ActivityInstrumentationTestCase2
et MockitoAnnotations.initMocks(this);
ne fonctionnait pas ..__ J'ai résolu ce problème avec une autre classe avec respectivement champ Par exemple:
class CaptorHolder {
@Captor
ArgumentCaptor<Callback<AuthResponse>> captor;
public CaptorHolder() {
MockitoAnnotations.initMocks(this);
}
}
Ensuite, dans la méthode de test d'activité:
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();