【问题标题】:Hamcrest compare collectionsHamcrest 比较系列
【发布时间】:2014-02-07 10:00:07
【问题描述】:

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


    【解决方案1】:

    如果你想断言这两个列表是相同的,不要用 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,该Matcher 期望匹配一个Iterable,其中每个元素 是一个List。这不能用于匹配List

    也就是说,您无法将 List&lt;Agent&gt;Matcher&lt;Iterable&lt;List&lt;Agent&gt;&gt; 匹配,这正是您的代码所尝试的。

    【讨论】:

    • +1 表示“如果你真的想用列表的内容调用相同的方法”。可悲的是,我自己无法解决这个问题。特别是有一个接受集合的构造函数。
    • @Tim 不完全; containsInAnyOrder 要求 all 元素都存在,因此第一个断言将失败。如果您想检查至少这些元素是否存在,请参阅hasItems
    • 如果您使用 containsInAnyOrder,您应该首先确保两个列表具有相同的大小...如果 actual.getList() 恰好包含 "item1", "item3", "item2",则测试将通过,也许您想确保它仅包含列出的项目...在这种情况下,您可以在 containsInAnyOrder 之前使用assertThat(actual.getList().size(), equalTo(2));,这样可以确保两个列表具有相同的内容。
    • @Martin 你在想hasItems。这里不需要额外的检查。请参阅上面对 Tim 的评论,以及 How do Hamcrest's hasItems, contains and containsInAnyOrder differ?
    • Kotlin 用户:当将数组作为可变参数传递时,不要忘记添加扩展运算符 (*expectedList.toTypedArray())!
    【解决方案2】:
    List<Long> actual = Arrays.asList(1L, 2L);
    List<Long> expected = Arrays.asList(2L, 1L);
    assertThat(actual, containsInAnyOrder(expected.toArray()));
    

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 如果列表项不是原始类型,这是一个很好的决定。
      • 有没有一种类型安全的方法来做到这一点?
      【解决方案4】:

      对于现有的 Hamcrest 库(从 v.2.0.0.0 开始),您必须在 Collection 上使用 Collection.toArray() 方法才能使用 containsInAnyOrder 匹配器。 将其作为单独的方法添加到 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());
      }
      

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

      【讨论】:

      • 不错,我会使用这个助手。这里的断言消息提供更多信息:它一个一个地命名丢失的项目,而不仅仅是:列表应该是 elem1、elem2、.. elem99,但我得到了 elem1、elem2、...、elem98——祝你好运找到丢失的那个。
      【解决方案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

      附:任何帮助避免被禁止的警告将不胜感激。

      【讨论】:

        【解决方案6】:

        确保列表中的Objects 上定义了equals()。那么

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

        有效。

        【讨论】:

          【解决方案7】:

          使用保留的顺序(严格顺序)比较两个列表。

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

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

          assertThat(collection, containsInAnyOrder("item1","item2"));
          

          【讨论】:

          • 这没有回答问题。
          • 部分是这样。
          • @rvazquezglez 你是什么意思?你为什么这么说?该方法的结果在我的环境中是正确的。
          • @niaomingjian 代码正在检查actualList 是否包含contains 匹配器中的元素,如果元素的顺序不同,则会失败,如果包含更多元素,也会失败或缺少一个。
          • @rvazquezglez 所以代码的目的是检查两个列表中的确切相等性(相同的长度、值和顺序),对吧?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多