Phi*_*das 35 java generics hamcrest mockito
我遇到了Mockito和Hamcrest的仿制问题.
请假设以下界面:
public interface Service {
void perform(Collection<String> elements);
}
Run Code Online (Sandbox Code Playgroud)
以下测试片段:
Service service = mock(Service.class);
// ... perform business logic
verify(service).perform(Matchers.argThat(contains("a", "b")));
Run Code Online (Sandbox Code Playgroud)
所以我想验证我的业务逻辑实际上是用一个包含"a"和"b"的集合来调用服务.
但是,返回类型contains(...)是Matcher<Iterable<? extends E>>,所以在我的情况下Matchers.argThat(...)返回Iterable<String>,这自然不适用于所需的Collection<String>.
我知道我可以使用Hamcrest hasItem和Mockito中提出的参数捕获器验证不一致,但我非常愿意不这样做.
有什么建议!谢谢!
Daw*_*ica 29
你可以写
verify(service).perform((Collection<String>) Matchers.argThat(contains("a", "b")));
Run Code Online (Sandbox Code Playgroud)
但从编译器的角度来看,这是铸造Iterable<String>到Collection<String>这是很好的,因为后者是前者的一个亚型.在运行时,argThat将返回null,以便可以传递给perform没有ClassCastException.关于它的重要一点是,匹配器进入Mockito的内部结构参数进行验证,这就是做什么的argThat.
如果您遇到类似这样的情况,请记住您可以编写一个非常小的可重用适配器.
verify(service).perform(argThat(isACollectionThat(contains("foo", "bar"))));
private static <T> Matcher<Collection<T>> isACollectionThat(
final Matcher<Iterable<? extends T>> matcher) {
return new BaseMatcher<Collection<T>>() {
@Override public boolean matches(Object item) {
return matcher.matches(item);
}
@Override public void describeTo(Description description) {
matcher.describeTo(description);
}
};
}
Run Code Online (Sandbox Code Playgroud)
请注意,David的上述解决方案,使用强制转换,是最简单的正确答案.
作为替代方案,可以将方法改为ArgumentCaptor:
@SuppressWarnings("unchecked") // needed because of `List<String>.class` is not a thing
// suppression can be worked around by using @Captor on a field
ArgumentCaptor<List<String>> captor = ArgumentCaptor.forClass(List.class);
verify(service).perform(captor.capture());
assertThat(captor.getValue(), contains("a", "b"));
Run Code Online (Sandbox Code Playgroud)
您可以将自己的 lambda 作为 ArgumentMatcher
when(myClass.myMethod(argThat(arg -> arg.containsAll(asList(1,2))))
.thenReturn(...);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
42299 次 |
| 最近记录: |