20

Ok I think its going to be a short question. I have an ArrayList that I sorted by date, of course I see it works but I would also like to write a test for it.

I want to check if next value (date) in my list is lower then previous one. I am able to do that with using some for s and adding temp list, but I'm wondering if there's a easier solution. I read in hamrest documentation that there's somethink like contains(hamrest contains) that iterate through an object (list,map etc) but still I have no idea what to do next.

4

7 回答 7

19

[第一个选项]:您可以编写自己的 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 的,但你可以Date很容易地用 s 来做。

[第二个选项],基于containsOP 问题中的参考:您可以创建第二个列表,订购原始列表,而不是使用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)
    ...
于 2013-11-06T15:11:46.737 回答
15

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

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;
});
于 2013-11-06T14:50:05.257 回答
12

也可以使用 GUAVA 进行检查:

import com.google.common.collect.Ordering;

...

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

此处提供更多信息:如何确定列表是否在 Java 中排序?

于 2017-01-13T10:13:53.477 回答
3

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

于 2013-11-06T14:50:16.050 回答
3

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

/**
 * 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();
    }
}
于 2014-10-30T10:54:39.193 回答
3

您可以使用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()));
}

于 2020-10-09T08:44:15.363 回答
0

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

如何使用 Hamcrest 检查集合是否包含给定顺序的项目

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

希望这可以帮助。

于 2015-06-18T12:17:36.957 回答