Mockito可以验证参数是否具有某些属性/字段?

时间:2015-08-13 16:13:27

标签: java unit-testing mocking mockito

说我在嘲笑这个班级Foo

class Foo {
  public void doThing(Bar bar) {
    // ...
  }
}

这是Bar

class Bar {
  private int i;
  public int getI() { return i; }
  public void setI(int i) { this.i = i; }
}

我知道我可以使用Mockito的验证功能来查看是否在模拟中使用Foo#doThing(Bar)的特定实例或Bar Bar来调用Mockito.any(Bar.class) },但有哪些方法可以确保它被Bar调用但具有iBar#getI()的特定值?

我所知道的可能性:

Foo mockedFoo = mock(Foo.class);
Bar someBar = mock(Bar.class);
...
verify(mockedFoo).doThing(someBar);
verify(mockedFoo).doThing(any(Bar.class);

我想知道的是,是否有办法验证具有特定事项的Bar是否作为参数传递。

4 个答案:

答案 0 :(得分:48)

Mockito 2.1.0以及Java 8中,您可以将lambda传递给argThat开箱即用,这样就不需要自定义参数匹配器了。对于OP中的示例将是:

verify(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));

这是因为从Mockito 2.1.0开始,ArgumentMatcher是一个功能界面。

答案 1 :(得分:15)

如果您使用的是Mockito 2.1.0或更高版本以及Java 8或更高版本,请参阅this答案,现在它更简单了。

我在写这个问题时找到了答案。

是的,你可以。例如,我们要检查any(Bar.class)是否为5,而不是使用i,您需要实现自己的ArgumentMatcher<T>实例并使用Mockito#argThat(Matcher)

// in the test (could also be outside)

private static final class BarIs5 extends ArgumentMatcher<Bar> {

  @Override
  public boolean matches(Object argument) {
    return ((Bar) argument).getI() == 5;
  }
}

然后验证:verify(mockedFoo).doThing(argThat(new BarIs5()));

通过添加构造函数参数来提升一个档次!

private static final class BarIsWhat extends ArgumentMatcher<Bar> {

  private final int i;

  public BarIsWhat(int i) {
    this.i = i
  }

  @Override
  public boolean matches(Object argument) {
    return ((Bar) argument).getI() == i;
  }
}

然后验证:verify(mockedFoo).doThing(argThat(new BarIsWhat(5)));

更新:由于徽章,我的队列中出现了这个问题,并且还有一些改进空间。

我试过这个并且它有效。你可以使用一个更清晰的lambda表达式(如果你不介意至少未经检查的强制转换警告)。

唯一的问题是argThat接受了一个Hamcrest Matcher 而不是一个@FunctionalInterface。幸运的是,Mockito的ArgumentMatcher是一个扩展它的抽象类,只有一个抽象方法。

在您的测试中(或某些常见位置)制作如下方法

private static <T> ArgumentMatcher<T> matches(Predicate<T> predicate) {
  return new ArgumentMatcher<T>() {

    @SuppressWarnings("unchecked")
    @Override
    public boolean matches(Object argument) {
      return predicate.test((T) argument);
    }
  };
}

现在,在测试中,您可以使用lambda表达式:

verify(mockedFoo).doThing(argThat(matches( (Bar arg) -> arg.getI() == 5 )));

答案 2 :(得分:5)

如果不能选择使用Mockito 2+,您也可以使用好的ArgumentCaptor。但它会更加冗长:

ArgumentCaptor<Long> siteIdCaptor = ArgumentCaptor.forClass(Long.class);
verify(repository).findBySiteId(siteIdCaptor.capture());
assertEquals(15, siteIdCaptor.getValue().longValue());

答案 3 :(得分:0)

如果您正在寻找when.. then..语法,这应该是一种可行的选择:

doReturn(valueToReturn).when(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));