Reputation: 31633
How to check using Hamcrest if given collection is containing given items in given order? I tried hasItems
but it simply ignores the order.
List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, hasItems("foo", "boo"));
//I want this to fail, because the order is different than in "list"
assertThat(list, hasItems("boo", "foo"));
Upvotes: 54
Views: 73542
Reputation: 748
You can combine is
and equalTo
of matchers library. The assert statement looks longer but the error message is better. Since contains
is fail first it breaks when it finds the first mismatch and wouldn't find failures further down the list. Where as is
and equalTo
will print the entire list from which you see all the mismatches.
Example using contains
List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, contains("foo", "boo", "bar"));
Gives the following error message:
Expected: iterable containing ["foo", "boo", "bar"]
but: item 1: was "bar"
Example using is and equalTo
List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, is(equalTo(Lists.newArrayList("foo", "boo", "bar"))));
Gives the following error message:
Expected: is <[foo, boo, bar]>
but: was <[foo, bar, boo]>
The second method doesn't tell you the index where the mismatch is but to me this is still better as you can fix the test by looking at the failure message just once. Whereas in method one, you'll first fix index 1, run the test, detect mismatch at index 2 and do the final fix.
Upvotes: 0
Reputation: 432
I found a solution at http://www.baeldung.com/hamcrest-collections-arrays
Look for the section that has an example with strict order.
List<String> collection = Lists.newArrayList("ab", "cd", "ef");
assertThat(collection, contains("ab", "cd", "ef"));
Basically you need to use the contains Matcher (org.hamcrest.Matchers.contains
)
Upvotes: 1
Reputation: 2107
To check tha collection contains items in expected (given) order you can use Hamcrest's containsInRelativeOrder
method.
From javadoc:
Creates a matcher for Iterable's that matches when a single pass over the examined Iterable yields a series of items, that contains items logically equal to the corresponding item in the specified items, in the same relative order For example: assertThat(Arrays.asList("a", "b", "c", "d", "e"), containsInRelativeOrder("b", "d")).
Actual for Java Hamcrest 2.0.0.0.
Hope this helps.
Upvotes: 10
Reputation: 8885
The accepted answer is not working for me. It still fails, saying
Expected: iterable containing ["foo", "boo"] but: Not matched: "bar"
So I wrote my own IsIterableContainingInRelativeOrder, and submitted it as a patch.
Upvotes: 1
Reputation: 135992
You need to implement a custom Matcher, something like this
class ListMatcher extends BaseMatcher {
String[] items;
ListMatcher(String... items) {
this.items = items;
}
@Override
public boolean matches(Object item) {
List list = (List) (item);
int l = -1;
for (String s : items) {
int i = list.indexOf(s);
if (i == -1 || i < l) {
return false;
}
l = i;
}
return true;
}
@Override
public void describeTo(Description description) {
// not implemented
}
}
@Test
public void test1() {
List<String> list = Arrays.asList("foo", "bar", "boo");
Assert.assertThat(list, new ListMatcher("foo", "boo"));
Assert.assertThat(list, new ListMatcher("boo", "foo"));
}
Upvotes: 2
Reputation: 20663
You can use contains
matcher instead, but you probably need to use latest version of Hamcrest. That method checks the order.
assertThat(list, contains("foo", "boo"));
You can also try using containsInAnyOrder
if order does not matter to you.
That's the code for contains
matcher:
public static <E> Matcher<Iterable<? extends E>> contains(List<Matcher<? super E>> itemMatchers)
{
return IsIterableContainingInOrder.contains(itemMatchers);
}
Upvotes: 65