2010-04-13 5 views
101

übereinstimmen ich versucht habe zu bekommen, ein Verfahren mit Vararg Parametern zu verspotten mit Mockito:Wie man richtig varargs in 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)); 

nicht funktioniert Dies gilt jedoch, wenn ich dies tun, statt:

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

Dies funktioniert, obwohl ich das varargs Argument beim Stubben der Methode vollständig weggelassen haben.

Irgendwelche Hinweise?

+0

Die Tatsache, dass das letzte Beispiel funktioniert, ist ziemlich trivial, da es mit dem Fall übereinstimmt, wenn null varargs-Parameter übergeben wurden. – topchef

Antwort

169

Mockito 1.8.1 anyVararg() matcher eingeführt:

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

auch Geschichte für diese sehen: https://code.google.com/archive/p/mockito/issues/62

+24

'anyVararg()' hat Objekt als Rückgabetyp. Um es mit allen Var-Typen (z. B. String ..., Integer ... usw.) kompatibel zu machen, führen Sie ein explizites Casting durch. Wenn Sie zum Beispiel 'doSomething (Integer number, String ... args) haben, können Sie den mock/stub Code mit etwas wie' when (mock) .doSomething (eq (1), (String) anyVarargs()) '. Das sollte den Kompilierungsfehler beheben. –

+9

für info anyVararg ist jetzt veraltet: "@deprecated ab 2.1.0 benutze any()" – alexbt

+2

'Matchers' ist nun veraltet, um einen Namenskonflikt mit' org.hamcrest.Matchers' Klasse zu vermeiden und wird wahrscheinlich in entfernt Mockito v3.0. Verwenden Sie stattdessen 'ArgumentMatchers'. – JonyD

24

Eine etwas nicht dokumentierte Funktion: Wenn Sie einen benutzerdefinierten Matcher entwickeln wollen, die Vararg Argumente, die Sie haben müssen passt zu es implementieren org.mockito.internal.matchers.VarargMatcher, damit es richtig funktioniert. Es ist ein leeres Marker-Interface, ohne das Mockito Argumente beim Aufruf einer Methode mit varargs nicht korrekt vergleicht.

Zum Beispiel:

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

Vielen Dank Eli, ich frage mich, warum das Mockito "Feature" eher versteckt ist ... –

5

Aufbauend auf Eli Levine Antwort hier ist eine generische Lösung:

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

} 

Dann können Sie es mit hamcrest des Arrays verwenden Matcher so:

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

(Offensichtlich werden statische Importe dies lesbarer machen.)

+0

Schön. Dies sollte in Mockito IMO eingebaut werden. – bryant

+0

Ich habe ein Problem gegen Hamcrest eingereicht, um so etwas hinzuzufügen. Siehe https://github.com/mockito/mockito/issues/356 – Mark

+0

Ist dies für Mockito 1? Ich bekomme verschiedene Kompilierungsfehler, wenn ich versuche, gegen 2.10 zu kompilieren. – Frans

1

Aufbauend auf TopChef Antwort,

Für 2.0.31-beta I Mockito.anyVararg statt Matchers.anyVararrg verwenden musste:

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

für info anyVararg ist jetzt veraltet: "@deprecated ab 2.1.0 benutze any()" – alexbt

0

die Signatur der Methode In meinem Fall, den ich will ihr Argument erfassen ist:

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

In diesem Fall Sie explizit Byte-Array werfen sollte:

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

Ich verwende Mockito Version 1.10.19

1

Ich habe in Peter Westmacott Antwort jedoch mit Mockito 2.2.15 den Code wurde verwenden, können Sie jetzt wie folgt vorgehen:

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

wo arg1, arg2, arg3 sind Varargs.

0

Sie können auch eine Schleife über die Argumente:

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

zum Beispiel ihre Typen überprüfen und sie in geeigneter Weise werfen, fügen Sie zu einer Liste oder was auch immer.