Mockito 可以验证一个参数是否具有特定的 properties/fields?
Can Mockito verify an argument has certain properties/fields?
说我在嘲笑这个classFoo
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 的验证功能来查看是否使用 Bar
的特定实例或任何带有 Mockito.any(Bar.class)
的 Bar
在 mock 上调用了 Foo#doThing(Bar)
, 但是有什么方法可以确保它被任何 Bar
调用但具有 i
或 Bar#getI()
的特定值?
我所知道的是可能的:
Foo mockedFoo = mock(Foo.class);
Bar someBar = mock(Bar.class);
...
verify(mockedFoo).doThing(someBar);
verify(mockedFoo).doThing(any(Bar.class);
我想知道的是,是否有一种方法可以验证 Bar
的特定内容是否作为参数传递。
如果您使用的是 Mockito 2.1.0 或更高版本以及 Java 8 或更高版本,请参阅 答案,现在更简单了。
我在写问题的时候找到了答案。
是的,你可以。您需要实现自己的 ArgumentMatcher<T>
and use Mockito#argThat(Matcher)
实例,而不是使用 any(Bar.class)
,例如,假设我们要检查 i
是 5...
// 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
是一个扩展它的抽象 class,并且只有一个抽象方法。
在您的测试(或一些常见位置)中创建如下方法
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 )));
在 Mockito 2.1.0 和 Java 8 中,您可以开箱即用地将 lambda 传递给 argThat 这样就不需要自定义参数匹配器.对于 OP 中的示例将是:
verify(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));
这是因为从 Mockito 2.1.0 开始,ArgumentMatcher
是一个函数式接口。
如果不能使用 Mockito 2+,您也可以使用旧的 ArgumentCaptor
。不过会有点冗长:
ArgumentCaptor<Long> siteIdCaptor = ArgumentCaptor.forClass(Long.class);
verify(repository).findBySiteId(siteIdCaptor.capture());
assertEquals(15, siteIdCaptor.getValue().longValue());
如果您正在寻找 when.. then..
语法,这应该是一个可行的替代方法:
doReturn(valueToReturn).when(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));
说我在嘲笑这个classFoo
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 的验证功能来查看是否使用 Bar
的特定实例或任何带有 Mockito.any(Bar.class)
的 Bar
在 mock 上调用了 Foo#doThing(Bar)
, 但是有什么方法可以确保它被任何 Bar
调用但具有 i
或 Bar#getI()
的特定值?
我所知道的是可能的:
Foo mockedFoo = mock(Foo.class);
Bar someBar = mock(Bar.class);
...
verify(mockedFoo).doThing(someBar);
verify(mockedFoo).doThing(any(Bar.class);
我想知道的是,是否有一种方法可以验证 Bar
的特定内容是否作为参数传递。
如果您使用的是 Mockito 2.1.0 或更高版本以及 Java 8 或更高版本,请参阅
我在写问题的时候找到了答案。
是的,你可以。您需要实现自己的 ArgumentMatcher<T>
and use Mockito#argThat(Matcher)
实例,而不是使用 any(Bar.class)
,例如,假设我们要检查 i
是 5...
// 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
是一个扩展它的抽象 class,并且只有一个抽象方法。
在您的测试(或一些常见位置)中创建如下方法
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 )));
在 Mockito 2.1.0 和 Java 8 中,您可以开箱即用地将 lambda 传递给 argThat 这样就不需要自定义参数匹配器.对于 OP 中的示例将是:
verify(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));
这是因为从 Mockito 2.1.0 开始,ArgumentMatcher
是一个函数式接口。
如果不能使用 Mockito 2+,您也可以使用旧的 ArgumentCaptor
。不过会有点冗长:
ArgumentCaptor<Long> siteIdCaptor = ArgumentCaptor.forClass(Long.class);
verify(repository).findBySiteId(siteIdCaptor.capture());
assertEquals(15, siteIdCaptor.getValue().longValue());
如果您正在寻找 when.. then..
语法,这应该是一个可行的替代方法:
doReturn(valueToReturn).when(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));