Java Mockito Matchers isA、any、eq 和 same 之间有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30890011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:19:58  来源:igfitidea点击:

What's the difference between Mockito Matchers isA, any, eq, and same?

javaunit-testingmockitodifferencematcher

提问by Silly Sally

I am confused on what's the difference between them, and which one to choose in which case. Some difference might be obvious, like anyand eq, but I'm including them all just to be sure.

我对它们之间的区别以及在这种情况下选择哪一个感到困惑。一些差异可能很明显,例如anyeq,但我将它们都包括在内是为了确定。

I wonder about their differences because I came across this problem: I have this POST method in a Controller class

我想知道它们的区别,因为我遇到了这个问题:我在 Controller 类中有这个 POST 方法

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

And would like to perform a unit test on that controller. I have two versions. The first one is the simple one, like this

并想对该控制器执行单元测试。我有两个版本。第一个是简单的,像这样

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

But I wanted to use a MockMvc approach, like this one

但我想使用 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")));
}

Both work well. But I wanted my someServiceMock.doSomething()in the MockMvc approach to receive req, or at least an object that has the same variable values as req(not just any Requestclass), and return res, just like the first. I know that it's impossible using the MockMvc approach (or is it?), because the object passed in the actual call is always different from the object passed in the mock. Is there anyway I can achieve that? Or does it even make sense to do that? Or should I be satisfied using any(Request.class)? I've tried eq, same, but all of them fail.

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

Thank you in advance. I hope I explained myself well.

先感谢您。我希望我能很好地解释自己。

采纳答案by Jeff Bowman

  • any()checks absolutely nothing. In Mockito 1.x, any(T.class)also checks absolutely nothing but also saves you a cast (prior to Java 8).

    This is due to change in Mockito 2.0 and beyond, when any(T.class)will share isAsemantics to mean "any T" or properly "any instance of type T". any()will still check absolutely nothing.

  • isA(T.class)checks that the argument instanceof T, implying it is non-null.

  • same(obj)checks that the argument is the same instance as obj, such that arg == objis true.

  • eq(obj)checks that the argument equals objaccording to its equalsmethod. This is also the behavior if you pass in real values without using matchers.

    Note that unless equalsis overridden, you'll see the default Object.equals implementation, which would have the same behavior as same(obj).

  • any()检查绝对没有。在 Mockito 1.x 中,any(T.class)也绝对不检查任何内容,但也为您节省了强制转换(Java 8 之前)。

    这是由于 Mockito 2.0 及更高版本中的更改,何时any(T.class)将共享isA语义以表示“任何T”或正确的“任何类型的实例T”。any()仍然绝对不会检查任何东西。

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

  • same(obj)检查参数是否与 相同的实例obj,这样arg == obj是真的。

  • eq(obj)obj根据其equals方法检查参数是否相等。如果您在不使用匹配器的情况下传递实际值,这也是行为。

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

If you need more exact customization, you can use an adapter for your own predicate:

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

  • For Mockito 1.x, use argThatwith a custom Hamcrest Matcher<T>that selects exactly the objects you need.
  • For Mockito 2.0 and beyond, use Matchers.argThatwith a custom org.mockito.ArgumentMatcher<T>, or MockitoHamcrest.argThatwith a custom Hamcrest Matcher<T>.
  • 对于 Mockito 1.x,argThat与自定义 Hamcrest 一起使用,以Matcher<T>准确选择您需要的对象。
  • 对于 Mockito 2.0 及更高版本,请Matchers.argThat与自定义org.mockito.ArgumentMatcher<T>MockitoHamcrest.argThat自定义 Hamcrest 一起使用Matcher<T>

回答by Alex Pruss

If your Request.class implements equals, then you can use eq():

如果你的 Request.class 实现了 equals,那么你可以使用 eq():

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

The above whenwould activate on

上面什么时候会激活

fooService.fooFxn(otherBar);

if

如果

otherBar.equals(bar);

Alternatively, if you want to the mock to work for some other subset of input (for instance, all Bars with Bar.getBarLength()>10), you could create a Matcher. I don't see this pattern too often, so usually I create the Matcher as a private class:

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

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

You would then use this matcher as follows:

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

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

Hope that helps!

希望有帮助!