[英]assertThat - hamcrest - check if list is sorted
好的,我认为这将是一个简短的问题。 我有一个按日期排序的 ArrayList,当然我认为它有效,但我也想为它编写一个测试。
我想检查列表中的下一个值(日期)是否低于前一个值。 我可以通过使用 some for
s 并添加临时列表来做到这一点,但我想知道是否有更简单的解决方案。 我在 hamrest 文档中读到有一些想法,比如contains
(hamrest contains),它遍历一个对象(列表、地图等),但我仍然不知道下一步要做什么。
[第一个选项] :您可以编写自己的匹配器。 类似于(免责声明:这只是一个示例代码,未经测试,可能并不完美):
@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;
}
};
}
此示例使用Integer
s,但您可以使用Date
轻松完成。
[Second option] ,基于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)
...
有这样一个 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;
});
也可以使用 GUAVA 来检查它:
import com.google.common.collect.Ordering;
...
assertTrue(Ordering.natural().isOrdered(list));
此处的更多信息: 如何确定列表是否在 Java 中排序?
对于小型集合,我建议提供在代码中硬编码的预期集合。 这是单元测试,不应包含任何逻辑。 之后,您可以比较两个集合。 (使用hamcrest
检查等效项)
我有一个类似的问题,我只是检查下一个以毫秒为单位的日期值是否大于/小于该列表中的前一个。
/**
* 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();
}
}
您可以使用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()));
}
您可以在另一个主题中查看我的答案,但方法保持不变 - 您应该检查项目是否按预期顺序排列。
如何使用 Hamcrest 检查集合是否包含按给定顺序的项目
这种方法需要使用“Hamcrest”库。
希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.