Hamcrest比较收藏品

xan*_*r27 100 java junit hamcrest

我想比较2个列表:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));
Run Code Online (Sandbox Code Playgroud)

但想法

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)
Run Code Online (Sandbox Code Playgroud)

我该怎么写呢?

Joe*_*Joe 143

如果你想断言两个列表是相同的,不要用Hamcrest复杂化:

assertEquals(expectedList, actual.getList());
Run Code Online (Sandbox Code Playgroud)

如果您真的打算执行顺序不敏感的比较,可以调用containsInAnyOrdervarargs方法并直接提供值:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));
Run Code Online (Sandbox Code Playgroud)

(假设你的列表是String,而不是Agent这个例子.)

如果你真的想用a的内容调用相同的方法List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));
Run Code Online (Sandbox Code Playgroud)

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

也就是说,您无法将a List<Agent>与a 匹配Matcher<Iterable<List<Agent>>,这正是您的代码尝试的内容.

  • 如果你使用containsInAnyOrder,你应该首先确保两个列表具有相同的大小...如果`actual.getList()`恰好包含`"item1","item3","item2"`,测试将通过,也许你想确保它只包含列出的项目...在这种情况下你可以使用`assertThat(actual.getList().size(),equalTo(2));`在containsInAnyOrder之前,这样你就可以确保列表具有相同的内容. (4认同)
  • @Tim不太好; `containsInAnyOrder`要求*all*元素存在,这样第一个断言就会失败.如果要检查*至少*那些元素是否存在,请参阅`hasItems`. (3认同)
  • @Martin 你在考虑 `hasItems`。这里不需要额外的检查。请参阅上面对 Tim 的评论,以及 [Hamcrest 的 hasItems、contains 和 containsInAnyOrder 有何不同?](http://stackoverflow.com/q/33840531/733345) (2认同)
  • **Kotlin 用户**:在将数组作为可变参数传递时,不要忘记添加扩展运算符 (`*expectedList.toTypedArray()`)! (2认同)

Jof*_*sey 55

List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));
Run Code Online (Sandbox Code Playgroud)

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


rva*_*lez 21

补充@ 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")))));
Run Code Online (Sandbox Code Playgroud)

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 ...)

  • 有没有类型安全的方法来做到这一点? (2认同)

yvo*_*olk 10

使用现有的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());
}
Run Code Online (Sandbox Code Playgroud)

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

  • 不错,我会用这个帮手。这里的断言消息提供更多信息:它一个一个地命名缺失的项目,不仅仅是:列表应该是 elem1、elem2、.. elem99,但我得到了 elem1、elem2、...、elem98——祝你好运找到丢失的那个。 (3认同)

bor*_*jab 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")))));
}
Run Code Online (Sandbox Code Playgroud)

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

PS 任何有助于避免被抑制的警告的帮助将不胜感激。