当前位置: 首页 > 知识库问答 >
问题:

hamcrest-比较集合中的项目

洪华皓
2023-03-14

有人能给我解释一下hamcrest是如何比较馆藏的,以及图书馆的不同方法是用来做什么的吗
我正在试图理解IsterableContainingAnyOrder#ContainingAnyOrder方法是如何工作的

ISiterableContainingAnyOrder类中有三个重载方法:

  • 包含InAnyOrder(T...项)
  • 包含InAnyOrder(匹配器

我的测试用例:

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),这是真的吗

但是如何使用中的剩余方法IsTerableContainingAnyOrder?有没有办法在不将集合转换为数组的情况下比较集合?


共有1个答案

巫马俊力
2023-03-14

您的代码在JDK1.8的第一种形式中编译得很好。0_12、Hamcrest 1.3和JUnit 4.12,尽管由于我将在下面解释的问题,它没有产生预期的结果。

我只能猜测,您可能有多种库版本,或jdk,或诸如此类的东西。然而,我相信这并不重要,因为我刚才提到的那个问题。

谁能给我解释一下hamcrest是如何比较收藏的,以及不同的方法是为了什么?

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

如果您检查源代码,您将看到ISiterableContainingAnyOrder构造函数接受一组匹配器:

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);
}

如你所见,为每个项目创建了一个匹配器,这有点像一个陷阱:

  • 如果您传递一个参数数组,您将获得每个项的匹配器

断言(实际,包含InAnyOrder(一,二,四));大喊:

java.lang.AssertionError: 
Expected: iterable over ["one", "two", "four"] in any order
     but: No item matches: "four" in ["two", "one"]
  • 如果您传递一个列表,它将计为一个1参数数组,并且仅为列表本身创建一个匹配器

断言(实际,包含InAnyOrder(rrays.as列表(一,二,四)))

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

注意到细微的差别了吗?

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

Matchers.containsInAnyOrder(expected.toArray()));我想在这种情况下,使用了库中的此方法:包含InAnyOrder(T...项),这是真的吗?

但是如何使用IsIterableContainingInAnyOrder中剩余的方法呢?有没有办法在不将集合转换为数组的情况下比较集合?

只需按原意使用内联表单assertThat(myList,包含任意顺序(“一”、“二”、“四”))。我认为这提供了更好的可读性,并避免了不必要的变量或多余的编码,例如预期的集合。通常你需要检查几个项目,而不是几百个,对吗?

 类似资料: