代码之家  ›  专栏  ›  技术社区  ›  qualidafial

如何正确匹配Mockito中的varargs

  •  124
  • qualidafial  · 技术社区  · 16 年前

    我一直在尝试使用Mockito来模拟一个带有vararg参数的方法:

    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参数,但这是有效的。

    有什么线索吗?

    8 回复  |  直到 16 年前
        1
  •  253
  •   pdem    8 年前

    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);
    
        2
  •  31
  •   Eli Levine    14 年前

    org.mockito.internal.matchers.VarargMatcher 让它正常工作。它是一个空的标记接口,没有它,Mockito在使用Matcher调用带有varargs的方法时将无法正确比较参数。

    例如:

    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);
    
        3
  •  8
  •   Rachel K. Westmacott    11 年前

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

    (显然,静态导入将使其更具可读性。)

        4
  •  3
  •   Mark    9 年前

    我一直在使用Peter Westmacott答案中的代码,但是对于Mockito 2.2.15,您现在可以执行以下操作:

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

    哪里 arg1, arg2, arg3

        5
  •  2
  •   NPike    10 年前

    基于topchef的答案,

    when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
    
        6
  •  0
  •   artronics    10 年前

    在我的例子中,我想要捕获其参数的方法的签名是:

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

    明确地:

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

    我用的是mockito版本 1.10.19

        7
  •  0
  •   Richard Whitehead    9 年前

    您还可以循环使用参数:

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

        8
  •  0
  •   Craig    7 年前

    改编@topchef的答案,

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

    根据Mockito 2.23.4的java文档,Mockito.any()匹配任何内容,包括null和varargs

        9
  •  0
  •   Clarke Lacher    7 年前

    您可以通过传递ArgumentCaptor捕获,然后使用“getAllValues”以列表形式检索varargs来完成此操作,请参见: https://stackoverflow.com/a/55621731/11342928

        10
  •  0
  •   sjngm quinti    5 年前

    由于其他的答案是有意义的,并且使测试工作很明显,所以我仍然建议测试方法时不要使用vararg,而是使用常规的定义良好的参数。这有助于处理与可能的不明确参数相关的重写方法,如SLF4J记录器:

    jobLogger.info("{} finished: {} tasks processed with {} failures, took {}", jobName, count, errors, duration);
    

    这有一堆重写,重要的方法是这样声明的

    Logger.info(String, Object...)
    

    验证:

    verify(loggerMock).info(anyString(), anyString(), anyInt(), anyInt(), anyString());
    

    errors 是一个整数而不是一个长的,因此无法运行以下命令:

    verify(loggerMock).info(anyString(), anyString(), anyInt(), anyLong(), anyString());
    

    when() 而不是 verify() -设置所需返回值。

    而且它可能显示了更多的意图和可读性。捕获也可以在这里使用,这样更容易访问。