كيفية مطابقة varargs بشكل صحيح في mockito
-
26-09-2019 - |
سؤال
كنت أحاول الحصول على السخرية من طريقة مع معلمات Vararg باستخدام 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));
هذا لا يعمل ، ولكن إذا قمت بذلك بدلاً من ذلك:
when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));
هذا يعمل ، على الرغم من أنني قد حذفت تمامًا وسيطة Varargs عند استخلاص الطريقة.
أي أدلة؟
المحلول
Mockito 1.8.1 قدم anyvararg () matcher:
when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);
انظر أيضا التاريخ لهذا: https://code.google.com/archive/p/mockito/issues/62
تعديل بناء جملة جديد بعد الإهمال:
when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);
نصائح أخرى
ميزة غير موثقة إلى حد ما: إذا كنت ترغب في تطوير مطابقة مخصصة يطابق وسائط Vararg التي تحتاجها لتنفيذها org.mockito.internal.matchers.VarargMatcher
لكي تعمل بشكل صحيح. إنها واجهة علامة فارغة ، والتي بدونها لن تقارن Mockito الوسيطات بشكل صحيح عند استدعاء طريقة مع Varargs باستخدام Matcher الخاص بك.
علي سبيل المثال:
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);
بناء إجابة إيلي ليفين هنا هو حل أكثر عامة:
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);
}
}
ثم يمكنك استخدامه مع متطابقات صفيف Hamcrest وهكذا:
verify(a).b(VarArgMatcher.varArgThat(
org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));
(من الواضح أن الواردات الثابتة ستجعل هذا أكثر قابلية للقراءة.)
لقد كنت أستخدم الكود في إجابة بيتر ويستموكوت ولكن مع Mockito 2.2.15 يمكنك الآن القيام بما يلي:
verify(a).method(100L, arg1, arg2, arg3)
أين arg1, arg2, arg3
هي varargs.
بناء على إجابة TopChef ،
لـ 2.0.31-beta ، اضطررت إلى استخدام mockito.anyvararg بدلاً من matchers.anyvararrg:
when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
في حالتي ، فإن توقيع الطريقة التي أريد التقاط حجتها هي:
public byte[] write(byte ... data) throws IOException;
في هذه الحالة يجب أن تلقي بها صفيف البايت صراحة:
when(spi.write((byte[])anyVararg())).thenReturn(someValue);
أنا أستخدم إصدار Mockito 1.10.19
يمكنك أيضًا حلقة الحجج:
Object[] args = invocation.getArguments();
for( int argNo = 0; argNo < args.length; ++argNo) {
// ... do something with args[argNo]
}
على سبيل المثال ، تحقق من أنواعها ويلقي بها بشكل مناسب ، أضف إلى قائمة أو أي شيء آخر.
تكييف الإجابة من topchef ،
Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);
وفقًا لمستندات Java لـ Mockito 2.23.4 و Mockito.any () "يطابق أي شيء ، بما في ذلك Nulls و Varargs."
يمكنك تحقيق ذلك عن طريق تمرير التقاط argumentCaptor ثم استرداد Varargs كقائمة باستخدام "GetAllValues" ، راجع: https://stackoverflow.com/a/55621731/11342928