谁能向我解释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"))
。我想这提供了更好的可读性,并避免了不必要的变量或多余的编码,例如预期的集合。通常您需要检查几件物品,而不是几百件,对吗?