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

2022-08-31 20:15:35

我在Mockito和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”的集合的服务。

但是,返回类型是 ,因此在我的情况下返回,这自然不适用于所需的。contains(...)Matcher<Iterable<? extends E>>Matchers.argThat(...)Iterable<String>Collection<String>

我知道我可以使用Hamcrest hasItem和Mockito验证不一致中提出的参数俘虏,但我非常希望不要这样做。

任何建议!谢谢!


答案 1

你可以只写

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

从编译器的角度来看,这是将 a 强制转换为 a 很好,因为后者是前者的子类型。在运行时,将返回 ,以便可以传递给没有 .关于它的重要一点是,匹配器进入了Mockito的内部验证参数结构,这就是它的作用。Iterable<String>Collection<String>argThatnullperformClassCastExceptionargThat


答案 2

作为替代方案,可以改变以下方法: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"));

请注意,作为副作用,这会将验证与Hamcrest库分离,并允许您使用任何其他库(例如Truth):

assertThat(captor.getValue()).containsExactly("a", "b");

推荐