Mockito 和 Hamcrest:如何验证 Collection 参数的调用?

2022-01-14 00:00:00 mockito java generics hamcrest

我遇到了 Mockito 和 Hamcrest 的泛型问题.

I'm running into a generics problem with Mockito and Hamcrest.

请假设如下界面:

public interface Service {
    void perform(Collection<String> elements);
}

还有下面的测试片段:

Service service = mock(Service.class);

// ... perform business logic

verify(service).perform(Matchers.argThat(contains("a", "b")));

所以我想验证我的业务逻辑是否真的使用包含a"和b"的集合来调用服务.

So I want to verify that my business logic actually called the service with a collection that contains "a" and "b" in that order.

但是contains(...)的返回类型是Matcher,所以 Matchers.argThat(...) 在我的情况下返回 Iterable<String> ,这自然不适用于所需集合.

However, the return type of contains(...) is Matcher<Iterable<? extends E>>, so Matchers.argThat(...) returns Iterable<String> in my case, which naturally does not apply to the required Collection<String>.

我知道我可以使用 Hamcrest hasItem and Mockito verify 中建议的参数捕获器不一致,但我非常不想这样做.

I know that I could use an argument captor as proposed in Hamcrest hasItem and Mockito verify inconsistency, but I would very much like not to.

任何建议!谢谢!

推荐答案

你可以写

verify(service).perform((Collection<String>) Matchers.argThat(contains("a", "b")));

从编译器的角度来看,这是将 Iterable<String> 转换为 Collection 这很好,因为后者是前任的.在运行时,argThat 将返回 null,因此可以在没有 ClassCastException 的情况下将其传递给 perform.重要的一点是,匹配器进入 Mockito 的内部参数结构进行验证,这就是 argThat 所做的.

From the compiler's point of view, this is casting an Iterable<String> to a Collection<String> which is fine, because the latter is a subtype of the former. At run time, argThat will return null, so that can be passed to perform without a ClassCastException. The important point about it is that the matcher gets onto Mockito's internal structure of arguments for verification, which is what argThat does.

相关文章