谁能向我解释hamcrest如何比较集合,以及库中使用的不同方法是什么?
我试图了解IsIterableContainingInAnyOrder#containsInAnyOrder方法如何工作。
IsIterableContainingInAnyOrder类中有三种重载方法:


containsInAnyOrder(T... items)
containsInAnyOrder(Matcher<? super T>... itemMatchers)
containsInAnyOrder(java.util.Collection<Matcher<? super T>> itemMatchers)


我的测试用例:

import org.hamcrest.Matchers;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.assertThat;

public class HamcrestCollections {

    @Test
    public void myTest(){

        List<String> expected = Arrays.asList("one","two","four");

        List<String> actual = Arrays.asList("two","one");

        // This doesn't compile
        assertThat(actual, Matchers.containsInAnyOrder(expected));

        assertThat(actual, Matchers.containsInAnyOrder(expected.toArray()));
    }
}


第一个断言不会编译,错误是:

Error:(19, 9) java: no suitable method found for assertThat(java.util.List<java.lang.String>,org.hamcrest.Matcher<java.lang.Iterable<? extends java.util.List<java.lang.String>>>)
    method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>) is not applicable
      (cannot infer type-variable(s) T
        (actual and formal argument lists differ in length))
    method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<? super T>) is not applicable
      (inferred type does not conform to upper bound(s)
        inferred: java.util.List<java.lang.String>
        upper bound(s): java.lang.Iterable<? extends java.util.List<java.lang.String>>,java.lang.Object)


我真的不明白此消息中发生了什么。



我发现它必须转换为数组才能工作(示例中的第二个断言):

Matchers.containsInAnyOrder(expected.toArray()));


我想在这种情况下,使用库中的这种方法:containsInAnyOrder(T... items),这是真的吗?
但是如何使用IsIterableContainingInAnyOrder中的其余方法?有什么方法可以比较集合而不将其转换为数组吗?

最佳答案

您的代码可以使用JDK 1.8.0_12,Hamcrest 1.3和JUnit 4.12在第一种形式中很好地进行编译,尽管由于出现陷阱而无法产生预期的结果,我将在下面进行解释。

我只能猜测您可能混合使用了库版本,jdk或某种形式的库。但是,我认为这并不重要,因为我刚才提到了这个陷阱。




  谁能向我解释hamcrest如何比较集合,以及库中使用的不同方法是什么?


简而言之,您可以提供自己的匹配器数组/集合,也可以为其创建匹配器的项目数组。之后,将根据结果匹配器列表验证实际项目。

如果选中the sources,您将看到IsIterableContainingInAnyOrder构造函数接受匹配器的集合:

public IsIterableContainingInAnyOrder(Collection<Matcher<? super T>> matchers) {
    this.matchers = matchers;
}


...而您想知道的方法是返回IsIterableContainingInAnyOrder实例的工厂方法。一个已弃用,我已跳过它。然后,我们得到以下2,其中第一个委托第二个,而没有任何幻想:

public static <T> Matcher<Iterable<? extends T>> containsInAnyOrder(Matcher<? super T>... itemMatchers) {
    return containsInAnyOrder(Arrays.asList(itemMatchers));
}

public static <T> Matcher<Iterable<? extends T>> containsInAnyOrder(Collection<Matcher<? super T>> itemMatchers) {
    return new IsIterableContainingInAnyOrder<T>(itemMatchers);
}


...最后,我们得到:

public static <T> Matcher<Iterable<? extends T>> containsInAnyOrder(T... items) {
    List<Matcher<? super T>> matchers = new ArrayList<Matcher<? super T>>();
    for (T item : items) {
        matchers.add(equalTo(item));
    }

    return new IsIterableContainingInAnyOrder<T>(matchers);
}


如您所见,将为每个项目创建一个匹配器,这有点像gotcha


如果传递参数数组,则每个项目都会有一个匹配项


assertThat(actual, containsInAnyOrder("one", "two", "four"));产量:

java.lang.AssertionError:
Expected: iterable over ["one", "two", "four"] in any order
     but: No item matches: "four" in ["two", "one"]



如果您传递一个列表,它将被视为1个参数数组,并且只会为列表本身创建1个匹配器


assertThat(actual, containsInAnyOrder(Arrays.asList("one", "two", "four")))产量:

java.lang.AssertionError:
Expected: iterable over [<[one, two, four]>] in any order
     but: Not matched: "two"


注意细微的差别吗?




  我发现必须将其转换为数组才能正常工作(
  示例中的第二个断言):
  
  Matchers.containsInAnyOrder(expected.toArray()));我想在
  在这种情况下,使用库中的此方法:containsInAnyOrder(T... items),这是真的吗?
  
  但是IsIterableContainingInAnyOrder中的其余方法如何
  用过的 ?有什么方法可以比较集合而不转换它们
  到阵列?


只需按预期使用内联形式:assertThat(myList, containsInAnyOrder("one", "two", "four"))。我想这提供了更好的可读性,并避免了不必要的变量或多余的编码,例如预期的集合。通常您需要检查几件物品,而不是几百件,对吗?

09-10 06:19