Hamcrest比较收藏


114

我正在尝试比较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)

我应该怎么写?

Answers:


161

如果要断言这两个列表相同,请不要使Hamcrest复杂化:

assertEquals(expectedList, actual.getList());

如果您确实打算执行不区分顺序的比较,则可以调用containsInAnyOrdervarargs方法并直接提供值:

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

(在此示例中String,假设您的列表属于,而不是Agent。)

如果您真的想使用a的内容调用相同的方法List

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

没有这一点,你调用一个参数的方法和创建Matcher一个期望匹配的Iterable,其中每个元素是一个List。不能用于匹配List

也就是说,您不能将a List<Agent>与匹配Matcher<Iterable<List<Agent>>,这是您的代码正在尝试的操作。


对于“如果您真的想使用列表的内容调用相同的方法”,则为+1。可悲的是我无法解决这个问题。特别是,有一个接受集合的构造函数。
伊亚德·易卜拉欣

3
@Tim不完全;containsInAnyOrder要求所有元素都存在,以便第一个断言将失败。看看hasItems是否要检查至少这些元素是否存在。
2015年

4
如果您使用containsInAnyOrder,则首先应确保两个列表的大小相同...如果actual.getList()碰巧包含了"item1", "item3", "item2",测试将通过,也许您想确保它仅包含列出的项目...在这种情况下,您可以使用assertThat(actual.getList().size(), equalTo(2));在containsInAnyOrder之前,可以确保两个列表具有相同的内容。
马丁

1
您正在考虑的@Martin hasItems。这里不需要额外的检查。请参阅上面对Tim的评论,以及Hamcrest的hasItems,contains和containsInAnyOrder有何不同?
2015年

1
Kotlin用户*expectedList.toTypedArray()在将数组作为varargs传递时,不要忘记添加传播运算符()!
詹姆斯·鲍曼

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

@Joe答案的较短版本,没有冗余参数。


28

为了补充@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 ...)


派对晚了一点,但是感谢您对每种方法之间差异的描述。
马科斯·德·安德拉德

如果列表项不是原始类型,则可以做出明智的决定。
斯坦尼斯拉夫·谢帕

有没有一种安全的方式可以做到这一点?
andresp

15

使用现有的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());
}

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


2
很好,我将使用此助手。此处的assert消息更具参考性:它逐个命名丢失的项,而不仅仅是:列表应该是elem1,elem2,.. elem99,但是我得到了elem1,elem2,...,elem98-祝您好运寻找失踪的人。
pihentagy


1

对于对象列表,您可能需要以下内容:

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

附言:避免出现警告的任何帮助将不胜感激。


-3

要将两个列表与保留的使用顺序进行比较,

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

这不能回答问题。
kamczak

它部分地做到了。
rvazquezglez

@rvazquezglez是什么意思?为什么这么说 该方法的结果恰好在我的环境中。
niaomingjian

@niaomingjian代码正在检查是否actualList包含containsmatcher 中的元素,如果元素的顺序不同,则该元素将失败,如果包含更多元素或缺少一个元素,则也将失败。
rvazquezglez

@rvazquezglez,所以代码的目的是检查两个列表中的确切相等性(长度,值和顺序相同),对吗?
niaomingjian
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.