【问题标题】:assertThat - hamcrest - check if list is sortedassertThat - hamcrest - 检查列表是否已排序
【发布时间】:2013-11-17 20:42:08
【问题描述】:

好的,我认为这将是一个简短的问题。我有一个按日期排序的 ArrayList,当然我认为它有效,但我也想为它编写一个测试。

我想检查列表中的下一个值(日期)是否低于上一个。我可以通过使用一些 for 并添加临时列表来做到这一点,但我想知道是否有更简单的解决方案。我在 hamrest 文档中读到,有些想法像 contains(hamrest contains) 会遍历一个对象(列表、地图等),但我仍然不知道下一步该做什么。

【问题讨论】:

  • 提供一些代码兄弟:)你可以快速获得帮助
  • 我没有提供任何代码,因为我认为我不必提供任何代码,因为我的问题是关于任何包含元素的列表(集合),我想将列表中的元素与同一列表中的下一个元素进行比较跨度>

标签: java junit hamcrest


【解决方案1】:

[First Option]:您可以编写自己的 Matcher。类似的东西(免责声明:这只是一个示例代码,未经测试,可能并不完美):

@Test
  public void theArrayIsInDescendingOrder() throws Exception
  {
    List<Integer> orderedList = new ArrayList<Integer>();
    orderedList.add(10);
    orderedList.add(5);
    orderedList.add(1);
    assertThat(orderedList, isInDescendingOrdering());
  }

  private Matcher<? super List<Integer>> isInDescendingOrdering()
  {
    return new TypeSafeMatcher<List<Integer>>()
    {
      @Override
      public void describeTo (Description description)
      {
        description.appendText("describe the error has you like more");
      }

      @Override
      protected boolean matchesSafely (List<Integer> item)
      {
        for(int i = 0 ; i < item.size() -1; i++) {
          if(item.get(i) <= item.get(i+1)) return false;
        }
        return true;
      }
    };
  }

此示例使用 Integers,但您可以轻松使用 Dates。

[第二个选项],基于 OP 问题中对contains 的引用:您可以创建第二个列表,对原始列表进行排序,而不是使用assertThat(origin, contains(ordered))。通过这种方式,可以更准确地描述最终的错误,因为如果某个元素不在预期的顺序中,则会指出它。比如这段代码

@Test
  public void testName() throws Exception
  {
    List<Integer> actual = new ArrayList<Integer>();
    actual.add(1);
    actual.add(5);
    actual.add(3);
    List<Integer> expected = new ArrayList<Integer>(actual);
    Collections.sort(expected);
    assertThat(actual, contains(expected.toArray()));
  }

将生成描述

java.lang.AssertionError: 
Expected: iterable containing [<1>, <3>, <5>]
     but: item 1: was <5>
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
    at org.junit.Assert.assertThat(Assert.java:865)
    at org.junit.Assert.assertThat(Assert.java:832)
    ...

【讨论】:

  • 第二个选项有效,因此第一个是矫枉过正/过于专业
  • 您将如何应用第二种解决方案来测试 Comparable 对象?
  • 与此同时,我现在越来越多地使用 AssertJ,它们提供了在进行断言时指定要使用的比较器的能力。我必须做一些研究才能提供 Hamcrest 解决方案。对不起
【解决方案2】:

有一个open request for such a matcher,但遗憾的是它还没有实现。

我会选择更简单的方法 - 复制列表,对其进行排序,然后与原始列表进行比较:

@Test
public void testListOrder() {
    ArrayList<SomeObject> original = ...;
    ArrayList<SomeObject> sorted = new ArrayList<SomeObject>(original);
    Collections.sort(sorted);
    Assert.assertEquals ("List is not sorted", sorted, original);
}

编辑:
@dsncode 在 cmets 中有一个优点 - 虽然(相对)优雅,但此解决方案的设计并未考虑任何性能考虑。如果列表不是太大,应该没问题,但如果列表很大,排序可能会很昂贵。如果列表很大,最好直接对其进行迭代,如果遇到小于前一个元素的元素,则测试失败。例如。:

assertTrue(() -> {
    Iterator<SomeClass> iter = list.iterator();

    SomeClass prev = null;
    if (iter.hasNext()) {
        prev = iter.next();
    }

    SomeClass curr = null;
    while (iter.hasNext()) {
        curr = iter.next();
        if (curr.compareTo(prev) < 0) {
            return false;
        }
        prev = curr;
    }

    return true;
});

【讨论】:

  • 是的,你是对的,它非常简单的解决方案,我只是想知道是否有办法只比较一个列表中的元素(例如,我的列表中有 20.01.1991 和 20.02.1991 并比较两者其中)
  • 不幸的是,通过排序,此解决方案将时间复杂度从线性时间检查增加到可能的 n^2。因此,如果测试的元素列表保证很小。那么它应该没问题。否则,我不建议这样做。
  • @dsncode 这是一个很好的观点——我希望代码简洁,假设您不会使用庞大的列表进行测试。我用 O(n) 断言的例子编辑了我的答案。
【解决方案3】:

也可以使用 GUAVA 进行检查:

import com.google.common.collect.Ordering;

...

assertTrue(Ordering.natural().isOrdered(list));

更多信息在这里:How to determine if a List is sorted in Java?

【讨论】:

    【解决方案4】:

    对于小型收藏,我建议提供以代码硬编码的预期收藏。 这是单元测试,不应包含任何逻辑。 之后,您可以比较两个集合。 (使用hamcrest 来检查等效项)

    【讨论】:

      【解决方案5】:

      我遇到了类似的问题,我只是检查下一个以毫秒为单位的日期值是否大于/小于该列表中的前一个。

      /**
       * Test sort by date
       */
      @Test
      public void findAllMessagesSortByDate() {
          Collection<Message> messages = messageService.getAllMessagesSortedByDate();
          long previousTime = messages.iterator().next().getDate().getTimeInMillis();
          for (Message message : messages) {
              assertTrue(message.getDate.getTimeInMillis() <= previousTime);
              previousTime = message.getMessageFolderTs().getTimeInMillis();
          }
      }
      

      【讨论】:

        【解决方案6】:

        您可以使用hamcrest-more-matchers(在Maven Central 上可用)。它有两种验证排序集合的实用方法:softOrdered(允许相等的顺序项)和strictOrdered(不允许相等的项)。 用法示例:

        import com.github.seregamorph.hamcrest.OrderMatchers.*;
        
        @Test
        public void softOrderedEqualShouldSuccess() {
            // success
            assertThat(Arrays.asList(1, 1, 2), softOrdered());
            // fails with diagnostics
            // java.lang.AssertionError: 
            // Expected: Strictly ordered by natural comparator
            //     but: Found equal elements 1 and 1
            assertThat(Arrays.asList(1, 1, 2), strictOrdered());
        }
        

        也可以嵌套:

        @Test
        public void nestedCollectionShouldMatchOrderedItem() {
            List<Iterable<Integer>> nested = Arrays.asList(
                    Arrays.asList(3, 2, 1),
                    Arrays.asList(1, 2, 3)
            );
        
            // success
            assertThat(nested, hasItem(strictOrdered()));
            // fails with diagnostics
            // java.lang.AssertionError:
            // Expected: every item is Softly ordered by natural comparator
            //     but: an item Found unordered elements 3 and 2
            assertThat(nested, everyItem(softOrdered()));
        }
        

        默认使用自然比较器,但也可以自定义:

        import static java.util.Comparator.comparing;
        
        @Test
        public void stringsShouldMatchOrderByLength() {
            List<String> list = Arrays.asList("abc", "ab", "a");
        
            assertThat(list, strictOrdered(comparing(String::length).reversed()));
        }
        
        

        【讨论】:

          【解决方案7】:

          您可以在另一个主题中查看我的答案,但方法保持不变 - 您应该检查项目是否符合预期的顺序。

          How to check if collection contains items in given order using Hamcrest

          这种方法需要使用“Hamcrest”库。

          希望这会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-14
            • 2011-06-10
            • 1970-01-01
            • 1970-01-01
            • 2017-11-20
            • 2012-04-08
            相关资源
            最近更新 更多