2010-04-13 6 views
101

J'ai essayé de se rendre à se moquer d'une méthode avec des paramètres de vararg utilisant Mockito:Comment faire correspondre correctement varargs à Mockito

interface A { 
    B b(int x, int y, C... c); 
} 

A a = mock(A.class); 
B b = mock(B.class); 

when(a.b(anyInt(), anyInt(), any(C[].class))).thenReturn(b); 
assertEquals(b, a.b(1, 2)); 

Cela ne fonctionne pas, si je fais ceci:

when(a.b(anyInt(), anyInt())).thenReturn(b); 
assertEquals(b, a.b(1, 2)); 

Cela fonctionne, bien que j'ai complètement omis l'argument varargs lors de l'encapsulation de la méthode.

Des indices?

+0

le fait que le dernier exemple fonctionne est plutôt trivial puisqu'il correspond au cas où les paramètres varargs zéro sont passés. – topchef

Répondre

169

Mockito 1.8.1 introduit anyVararg() matcher:

when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b); 

Voir aussi l'histoire pour cela: https://code.google.com/archive/p/mockito/issues/62

+24

'anyVararg()' a Object comme type de retour. Pour le rendre compatible avec tous les types var arg (par exemple String ..., Integer ..., etc.), faites un casting explicite. Par exemple, si vous avez 'doSomething (nombre entier, String ... args)' vous pouvez faire le code simulacre/stub avec quelque chose comme 'when (mock) .doQuelque chose (eq (1), (String) anyVarargs()) '. Cela devrait prendre soin de l'erreur de compilation. –

+9

pour info anyVararg est maintenant obsolète: "@deprecated à partir du 2.1.0 use any()" – alexbt

+2

'Matchers' est maintenant obsolète afin d'éviter un conflit de noms avec la classe' org.hamcrest.Matchers' et sera probablement supprimé dans mockito v3.0. Utilisez 'ArgumentMatchers' à la place. – JonyD

24

Une caractéristique peu non documentée: Si vous voulez développer un matcher personnalisé qui correspond à des arguments vararg vous devez il met en œuvre org.mockito.internal.matchers.VarargMatcher pour qu'il fonctionne correctement. C'est une interface de marqueur vide, sans laquelle Mockito ne comparera pas correctement les arguments lors de l'invocation d'une méthode avec varargs en utilisant votre Matcher.

Par exemple:

class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher { 
    @Override public boolean matches(Object varargArgument) { 
     return /* does it match? */ true; 
    } 
} 

when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b); 
+0

Merci beaucoup Eli, je me demande pourquoi cette 'fonctionnalité' de Mockito est plutôt cachée ... –

5

Miser sur la réponse de Eli Levine est ici une solution plus générique:

import org.hamcrest.Description; 
import org.hamcrest.Matcher; 
import org.mockito.ArgumentMatcher; 
import org.mockito.internal.matchers.VarargMatcher; 

import static org.mockito.Matchers.argThat; 

public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher { 

    public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) { 
     argThat(new VarArgMatcher(hamcrestMatcher)); 
     return null; 
    } 

    private final Matcher<T[]> hamcrestMatcher; 

    private VarArgMatcher(Matcher<T[]> hamcrestMatcher) { 
     this.hamcrestMatcher = hamcrestMatcher; 
    } 

    @Override 
    public boolean matches(Object o) { 
     return hamcrestMatcher.matches(o); 
    } 

    @Override 
    public void describeTo(Description description) { 
     description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher); 
    } 

} 

Ensuite, vous pouvez l'utiliser avec le tableau de hamcrest Matchers ainsi:

verify(a).b(VarArgMatcher.varArgThat(
      org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test"))); 

(De toute évidence, les importations statiques rendront ceci plus lisible.)

+0

Nice. Cela devrait être construit dans Mockito IMO. – bryant

+0

J'ai déposé un problème contre Hamcrest pour ajouter quelque chose comme ça. Voir https://github.com/mockito/mockito/issues/356 – Mark

+0

Est-ce pour Mockito 1? Je reçois diverses erreurs de compilation en essayant de compiler contre 2.10. – Frans

1

Miser sur la réponse de Topchef,

Pour 2.0.31-beta je devais utiliser Mockito.anyVararg au lieu de Matchers.anyVararrg:

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b); 
+2

pour info anyVararg est maintenant obsolète: "@deprecated à partir du 2.1.0 use any()" – alexbt

0

Dans mon cas, la signature de la méthode que je veux saisir son argument est:

public byte[] write(byte ... data) throws IOException; 

Dans ce cas, vous devriez jeter à tableau d'octets explicitement:

 when(spi.write((byte[])anyVararg())).thenReturn(someValue); 

J'utilise la version Mockito 1.10.19

1

J'utilise le code dans la réponse de Peter Westmacott mais avec Mockito 2.2.15, vous pouvez maintenant effectuer les opérations suivantes:

verify(a).method(100L, arg1, arg2, arg3)

arg1, arg2, arg3 sont varargs.

0

Vous pouvez également boucle sur les arguments:

Object[] args = invocation.getArguments(); 
for(int argNo = 0; argNo < args.length; ++argNo) { 
    // ... do something with args[argNo] 
} 

par exemple vérifier leurs types et les entraînes de manière appropriée, ajouter à une liste ou autre chose.

Questions connexes