Mockito Matchers isA,any,eq和eq之间的区别是什么?

我对它们之间的区别以及在这种情况下选择哪一种感到困惑。有些区别可能是显而易见的,比如 和 ,但我把它们都包括在内只是为了确定。anyeq

我想知道它们的差异,因为我遇到了这个问题:我在控制器类中有这个POST方法

public Response doSomething(@ResponseBody Request request) {
    return someService.doSomething(request);
}

并希望在该控制器上执行单元测试。我有两个版本。第一个是简单的一个,就像这样

@Test
public void testDoSomething() {
    //initialize ObjectMapper mapper
    //initialize Request req and Response res
    
    when(someServiceMock.doSomething(req)).thenReturn(res);

    Response actualRes = someController.doSomething(req);
    assertThat(actualRes, is(res));
}

但是我想使用MockMvc方法,就像这个

@Test
public void testDoSomething() {
    //initialize ObjectMapper mapper
    //initialize Request req and Response res
    
    when(someServiceMock.doSomething(any(Request.class))).thenReturn(res);

    mockMvc.perform(post("/do/something")
            .contentType(MediaType.APPLICATION_JSON)
            .content(mapper.writeValueAsString(req))
    )
            .andExpect(status().isOk())
            .andExpect(jsonPath("$message", is("done")));
}

两者都运行良好。但是我希望我在 MockMvc 方法中接收 ,或者至少是一个具有与 (不仅仅是任何类) 相同的变量值的对象,并返回 ,就像第一个一样。我知道使用MockMvc方法是不可能的(或者它是吗?),因为在实际调用中传递的对象总是与在模拟中传递的对象不同。无论如何,我能做到这一点吗?或者这样做有意义吗?还是我应该满意使用?我试过了 ,但都失败了。someServiceMock.doSomething()reqreqRequestresany(Request.class)eqsame


答案 1
  • any() 绝对不检查任何内容。从 Mockito 2.0 开始,any(T.class) 共享语义来表示“任何”或正确地表示“任何类型的实例”。isATT

    与 Mockito 1.x 相比,这是一个变化其中 any(T.class) 在 Java 8 之前只检查了一个强制转换:“任何种类的对象,都不是给定类所必需的。提供类参数只是为了避免强制转换。

  • isA(T.class) 检查参数,暗示它是非空的。instanceof T

  • same(obj) 检查参数是否引用与 相同的实例,例如 是否为 true。objarg == obj

  • eq(obj) 检查参数是否根据其方法相等。如果您不使用匹配器传入实值,这也是行为。objequals

    请注意,除非被覆盖,否则您将看到默认的 Object.equals 实现,该实现的行为与 相同。equalssame(obj)

如果需要更精确的自定义,可以将适配器用于自己的谓词:

  • 对于 Mockito 1.x,将 argThat 与自定义 Hamcrest 结合使用,该 Hamcrest 可准确选择您需要的对象。Matcher<T>
  • 对于 Mockito 2.0 及更高版本,请使用 Matchers.argThat 和自定义 ,或将 MockitoHamcrest.argThat 与自定义 Hamcrest 一起使用。org.mockito.ArgumentMatcher<T>Matcher<T>

您也可以使用refEq,它使用反射来确认对象相等性;Hamcrest具有与SamePropertyValuesA类似的实现,用于公共bean样式的属性。请注意,在 GitHub 问题 #1800 上建议弃用和删除 refEq,与该问题一样,您可能更愿意更好地为类提供更好的封装,而不是它们的平等感。eq


答案 2

如果你的请求.class实现等于,那么你可以使用 eq():

Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...

以上何时会激活

fooService.fooFxn(otherBar);

如果

otherBar.equals(bar);

或者,如果你想让模拟用于其他一些输入子集(例如,所有带有 Bar.getBarLength()>10 的柱线),你可以创建一个 Matcher。我不经常看到这种模式,所以通常我会将 Matcher 创建为私有类:

private static class BarMatcher extends BaseMatcher<Bar>{
...//constructors, descriptions, etc.
  public boolean matches(Object otherBar){
     //Checks, casts, etc.
     return otherBar.getBarLength()>10;
  }
}

然后,您将按如下方式使用此匹配器:

when(fooService.fooFxn(argThat(new BarMatcher())).then...

希望有所帮助!


推荐