2010-04-13 16 views
101

Próbowałem dostać się do mock metodę z użyciem parametrów vararg Mockito:Jak prawidłowo dopasować varargs w 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)); 

ten nie działa, więc jeśli mogę to zrobić w zamian:

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

To działa, pomimo tego, że całkowicie pominąłem argument varargs po upuszczeniu metody.

Jakieś wskazówki?

+0

fakt, że ostatni przykład działa, jest dość trywialny, ponieważ pasuje do przypadku, gdy parametry zera varargs przeszły. – topchef

Odpowiedz

169

Mockito 1.8.1 wprowadzono anyVararg() matcher:

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

Zobacz także historię tego: https://code.google.com/archive/p/mockito/issues/62

+24

'anyVararg()' ma obiekt jako typ zwracany. Aby uczynić go kompatybilnym z dowolnymi typami argumentów var (np. String ..., Integer ..., itp.), Wykonaj wyraźny rzut. Na przykład, jeśli masz 'doSomething (liczba całkowita, łańcuch ... args)' możesz zrobić makiety/kod pośredniczący z czymś takim jak 'when (mock) .doSomething (eq (1), (String) anyVarargs()) '. To powinno zająć się błędem kompilacji. –

+9

dla informacji anyVararg jest teraz uznawane za przestarzałe: "@deprecated od 2.1.0 używaj dowolnej()" – alexbt

+2

"Matchers" jest teraz przestarzałe, aby uniknąć konfliktu nazwy z klasą "org.hamcrest.Matchers" i prawdopodobnie zostanie usunięte w mockito v3.0. Zamiast tego użyj 'ArgumentMatchers'. – JonyD

24

nieco nieudokumentowanych funkcji: Jeśli chcesz rozwijać własny Matcher pasujący vararg argumentów musisz mieć implementuje on org.mockito.internal.matchers.VarargMatcher, aby działał poprawnie. Jest to pusty interfejs znacznika, bez którego Mockito nie będzie poprawnie porównywał argumentów podczas wywoływania metody z varargs przy użyciu Matchera.

Na przykład:

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

Wielkie dzięki Eli, zastanawiam się, dlaczego ta funkcja Mockito jest raczej ukryta ... –

5

Opierając się na odpowiedź Eli Levine'a o to bardziej ogólne rozwiązanie:

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

} 

Następnie można używać go z tablicy hamcrest za dopasowujące tak:

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

(Oczywiście, że statyczny import uczyni to bardziej czytelnym.)

+0

Nice. To powinno być wbudowane w IMO Mockito. – bryant

+0

Złożyłem sprawę przeciwko Hamcrestowi, aby dodać coś takiego. Zobacz https://github.com/mockito/mockito/issues/356 – Mark

+0

Czy to jest dla Mockito 1? Dostaję różne błędy kompilacji podczas próby kompilacji przeciwko 2.10. – Frans

1

Opierając się na odpowiedź topchef, w

Dla 2.0.31 beta musiałem użyć Mockito.anyVararg zamiast Matchers.anyVararrg:

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

dla informacji anyVararg jest teraz uznawane za przestarzałe: "@deprecated od wersji 2.1.0 użyj dowolnej()" – alexbt

0

W moim przypadku podpis metody, które chcę uchwycić swój argument brzmi:

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

W tym przypadku należy przesyłać bajtów tablicy extenso:

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

używam wersji Mockito 1.10.19

1

I zostały przy użyciu kodu w odpowiedzi Petera Westmacott jest jednak z Mockito 2.2.15 można teraz wykonać następujące czynności:

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

gdzie arg1, arg2, arg3 są varargs.

0

Można również pętla nad argumentami:

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

na przykład sprawdzić swoje typy i oddać je odpowiednio, dodać do listy lub cokolwiek innego.