Hamcrest 比较集合

问题描述 投票:0回答:8

我正在尝试比较 2 个列表:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

但是想法

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

我该怎么写呢?

java junit hamcrest
8个回答
204
投票

如果您想断言两个列表相同,请不要使用 Hamcrest 让事情变得复杂:

assertEquals(expectedList, actual.getList());

如果您确实打算执行不区分顺序的比较,可以调用

containsInAnyOrder
varargs 方法并直接提供值:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(在此示例中,假设您的列表是

String
,而不是
Agent
。)

如果您确实想使用

List
的内容调用相同的方法:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

如果没有这个,您将使用单个参数调用该方法并创建一个

Matcher
,它期望与
Iterable
匹配,其中 每个元素 是一个
List
。这不能用于匹配
List

也就是说,您无法将

List<Agent>
Matcher<Iterable<List<Agent>>
匹配,而这正是您的代码正在尝试的。


84
投票
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

@Joe 答案的简短版本,没有多余的参数。


51
投票

补充@Joe的答案:

Hamcrest 为您提供了四种主要的列表匹配方法:

contains
检查考虑顺序的所有元素是否匹配。如果列表的元素较多或较少,就会失败

containsInAnyOrder
检查所有元素是否匹配,顺序无关紧要。如果列表有更多或更少的元素,将会失败

hasItems
仅检查指定对象,列表是否有更多对象并不重要

hasItem
仅检查一个对象,列表是否有更多对象并不重要

它们都可以接收对象列表并使用

equals
方法进行比较,或者可以与其他匹配器混合使用,如@borjab提到的:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains(E...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#containsInAnyOrder(java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems(T...)


21
投票

使用现有的 Hamcrest 库(从 v.2.0.0.0 开始),您必须在 Collection 上使用 Collection.toArray() 方法才能使用 containsInAnyOrder Matcher。 更好的方法是将其作为单独的方法添加到 org.hamcrest.Matchers 中:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

实际上,我最终将此方法添加到我的自定义测试库中,并使用它来提高测试用例的可读性(由于不太冗长)。


5
投票

对于对象列表,您可能需要这样的东西:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

如果您不想检查对象的顺序,请使用containsInAnyOrder

附注任何避免被抑制的警告的帮助将非常感激。


4
投票

确保列表中的

Object
已定义
equals()
。然后

assertThat(generatedList, is(equalTo(expectedList)));

有效。


0
投票

如果您没有重复项(即,如果可以选择“设置比较”):

    // check for duplicates
    assertEquals(new HashSet<>(actual).size(), actual.size(), "Duplicate exists");

    // check if there are excess elements in `actual`
    HashSet<String> excess = new HashSet<>(actual);
    excess.removeAll(new HashSet<>(expected));
    assertThat(excess, Matchers.empty());

    // check if `actual` lacks any elements
    HashSet<String> lack = new HashSet<>(expected);
    lack.removeAll(new HashSet<>(actual));
    assertThat(lack, Matchers.empty());

Hamcrest 的

containsInAnyOrder()
错误消息有点难以处理 - 很高兴知道哪些元素过量以及哪些元素缺少。


-6
投票

要比较两个列表并保留顺序(严格顺序),请使用。

assertThat(actualList, contains("item1","item2"));

如果我们想在没有特定顺序的情况下进行比较,我们可以使用以下命令

assertThat(collection, containsInAnyOrder("item1","item2"));
© www.soinside.com 2019 - 2024. All rights reserved.