Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Mockito和Hamcrest:如何验证集合参数的调用?_Java_Generics_Mockito_Hamcrest - Fatal编程技术网

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

Java Mockito和Hamcrest:如何验证集合参数的调用?,java,generics,mockito,hamcrest,Java,Generics,Mockito,Hamcrest,我遇到了Mockito和Hamcrest的泛型问题 请假定以下接口: public interface Service { void perform(Collection<String> elements); } 因此,我想验证我的业务逻辑是否实际使用一个按顺序包含“a”和“b”的集合调用了服务 但是,contains(…)的返回类型是Matcher,您可以有自己的java.util.Collection实现,并覆盖equals方法,如下所示 public interfac

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

请假定以下接口:

public interface Service {
    void perform(Collection<String> elements);
}
因此,我想验证我的业务逻辑是否实际使用一个按顺序包含“a”和“b”的集合调用了服务


但是,
contains(…)
的返回类型是
Matcher,您可以有自己的java.util.Collection实现,并覆盖equals方法,如下所示

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

@Test
public void testName() throws Exception {
    Service service = mock(Service.class);
    service.perform(new HashSet<String>(Arrays.asList("a","b")));
    Mockito.verify(service).perform(Matchers.eq(new CollectionVerifier<String>(Arrays.asList("a","b"))));
}

public class CollectionVerifier<E> extends ArrayList<E> {

    public CollectionVerifier() {

    }

    public CollectionVerifier(final Collection<? extends E> c) {
        super(c);
    }

    @Override
    public boolean equals(final Object o) {
        if (o instanceof Collection<?>) {
            Collection<?> other = (Collection<?>) o;
                return this.size() == other.size() && this.containsAll(other);
        }
        return false;
    }

}
公共接口服务{
无效执行(收集元素);
}
@试验
public void testName()引发异常{
服务=模拟(Service.class);
perform(新的HashSet(Arrays.asList(“a”、“b”));
Mockito.verify(service).perform(Matchers.eq(newcollectionverifier(Arrays.asList(“a”,“b”))));
}
公共类CollectionVerifier扩展了ArrayList{
公共收集验证程序(){
}
公开收集验证人(最终收集){
集合其他=(集合)o;
返回this.size()==other.size()&&this.containsAll(other);
}
返回false;
}
}

如果遇到这种情况,请记住,您可以编写一个非常小的可重用适配器

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);
    }
  };
}
验证(服务)。执行(argThat(isACollectionThat(包含(“foo”、“bar”))));
私有静态匹配器是一个集合(

final Matcher为什么不使用预期参数进行验证,假设列表只包含两项,例如:

final List<String> expected = Lists.newArrayList("a", "b");
verify(service).perform(expected);
final List expected=Lists.newArrayList(“a”、“b”);
验证(服务)。执行(预期);
虽然我原则上同意Eugen的观点,但我认为依靠equals进行字符串比较是可以接受的……此外,
包含的
匹配器使用equals进行比较。

您只需编写

verify(service).perform((Collection<String>) Matchers.argThat(contains("a", "b")));
verify(service).perform((Collection)Matchers.argThat(包含(“a”、“b”));

从编译器的角度来看,这是将
Iterable
转换为
集合
,这很好,因为后者是前者的子类型。在运行时,
argThat
将返回
null
,这样就可以在不使用
ClassCastException
的情况下将其传递到
perform
但是,匹配器会进入Mockito的内部参数结构进行验证,这就是
arg所做的。

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

您可以将自己的lambda作为
ArgumentMatcher

when(myClass.myMethod(argThat(arg -> arg.containsAll(asList(1,2))))
    .thenReturn(...);

Matcher
强制转换为
Matcher
?这肯定不会编译…如果您知道集合类型,并且集合具有正确的
equals
实现,那么您可以使用包含“a”和“b”的集合实例调用
verify
。但这将是一个糟糕的测试-首先,您将分解实现细节你必须使用正确的equals方法。所以我会毫无疑问地使用参数捕捉器。我不知道要避免参数捕捉器,你会走多远,但也许你可以实现一个自定义匹配器,如
IsListOfTwoElements
:谢谢你的建议。毫不奇怪,我不喜欢它们中的任何一个。我想我必须使用这些参数毕竟是ument captors.:-(您无法验证
集合
上的“顺序”,因为
集合
不保证是有序集合。您确定是指集合而不是
列表
?@David您应该:)欢迎您在事后访问,以获得适当的信任。感谢您的回答以及Mockito matchers返回
null
的提示。如果@DavidWallace确实添加了他的评论作为回复,我将接受他的回答。希望您不会介意。:-@Philupp这是公平的!他只是回答了,FWIW,所以我正在编辑我的,以避免重复。
contains
返回一个
匹配项,其中包含您使用的内容?我只查找包含(字符串子字符串)的数据,以便使其保持最新;使用Kotlin执行此操作的一个简单方法是:
verify(service).perform(argThat{“b”==this[“a”]})
@barracuda317他们正在使用org.hamcrest.Matchers.contains()。我设法用org.hamcrest.CoreMatchers.hasItems()解决了这个问题。由于mockito 2.1.0,您需要使用MockitoHamcrest.argThat。令人惊叹的!如果要检查空集合,可以使用
argThat(collection::isEmpty)
assertThat(captor.getValue()).containsExactly("a", "b");
when(myClass.myMethod(argThat(arg -> arg.containsAll(asList(1,2))))
    .thenReturn(...);