web-dev-qa-db-fra.com

Comment faire correspondre les varargs dans Mockito

J'essayais de simuler une méthode avec des paramètres vararg en utilisant 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, cependant si je le fais à la place:

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

Cela fonctionne, malgré que j’ai complètement omis l’argument varargs lors de l’arrêt de la méthode.

Des indices?

123
qualidafial

Mockito 1.8.1 introduit anyVararg () Matcher :

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

Consultez également l'historique de cette opération: https://code.google.com/archive/p/mockito/issues/62

Edit nouvelle syntaxe après dépréciation:

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);
195
topchef

Une fonctionnalité quelque peu non documentée: si vous souhaitez développer un Matcher personnalisé qui corresponde aux arguments vararg, vous devez le faire implémenter 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'appel d'une méthode avec varargs à l'aide de 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);
28
Eli Levine

S'appuyant sur la réponse d'Eli Levine, voici 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 les tableaux de correspondance de hamcrest ainsi:

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

(Évidemment, les importations statiques rendront ceci plus lisible.)

5
Peter Westmacott

S'appuyant sur la réponse de topchef,

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

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
1
NPike

Adapter la réponse de @topchef, 

Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);

Selon les docs Java pour Mockito 2.23.4, Mockito.any () "Correspond à tout, y compris les valeurs null et varargs."

0
Craig

Dans mon cas, la signature de la méthode dont je veux capturer l'argument est la suivante:

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

Dans ce cas, vous devriez lancer vers tableau d'octets explicitement:

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

J'utilise la version 1.10.19 de mockito

Vous pouvez également parcourir les arguments:

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

par exemple, vérifiez leurs types et les diffusez correctement, ajoutez-les à une liste ou quoi que ce soit.

0
Richard Whitehead