1. Introduction
Hamcrest is a popular framework for writing matcher objects in Java, providing an expressive way to define match conditions. Matchers like hasItems(), contains(), and containsInAnyOrder() allow us to assert the presence and order of elements within a collection. In this tutorial, we’ll delve into what each of these matchers does, how they differ, and when to use them.
2. Element Ordering
In this section, we’ll explore how hasItems(), contains(), and containsInAnyOrder() treat the order of elements within a collection.
2.1. hasItems()
The hasItems() matcher is designed to check if a collection contains specific elements, without caring about their order:
List<String> myList = Arrays.asList("apple", "banana", "cherry");
assertThat(myList, hasItems("apple", "cherry", "banana"));
assertThat(myList, hasItems("banana", "apple", "cherry"));
2.2. containsInAnyOrder()
Similarly to hasItems(), containsInAnyOrder() doesn’t consider element order. It only cares that the specified items are present in the collection, regardless of their sequence:
assertThat(myList, containsInAnyOrder("apple", "cherry", "banana"));
assertThat(myList, containsInAnyOrder("banana", "apple", "cherry"));
2.3. contains()
In contrast, the contains() matcher is order-sensitive. It verifies that the collection contains the exact specified items in the same order they’re provided:
assertThat(myList, contains("apple", "banana", "cherry"));
assertThat(myList, not(contains("banana", "apple", "cherry")));
The first assertion passes because the elements’ order matches exactly. In the second assertion, we use the not() matcher, which expects that myList doesn’t contain elements in the exact order.
3. Exact Element Count
In this section, we’ll discuss how hasItems(), contains(), and containsInAnyOrder() handle the exact number of elements in a collection.
3.1. hasItems()
The hasItems() matcher doesn’t require the collection to have an exact count of elements. It focuses on ensuring the presence of specific items without imposing strict requirements on order or collection size:
assertThat(myList, hasItems("apple", "banana"));
assertThat(myList, hasItems("apple", "banana", "cherry"));
assertThat(myList, not(hasItems("apple", "banana", "cherry", "date")));
In the first assertion, we verify that myList contains both “apple” and “banana“. Since both items are present, the assertion passes. Similarly, the second assertion checks for the presence of “apple“, “banana“, and “cherry“, which are all present in the list, so it also passes.
However, the third assertion includes an extra element “date” which isn’t in myList. As a result, the not() matcher return succeeds. This illustrates that while hasItems() is flexible in verifying the presence of elements, it flags an assertion if extra items beyond those specified are found in the collection.
3.2. containsInAnyOrder()
While hasItems() allows for at least some of the specified items, the containsInAnyOrder() matcher requires the collection to contain all the items on our list. Regardless of the ordering, as long as all the specified items are present, the assertion passes:
assertThat(myList, containsInAnyOrder("apple", "banana", "cherry"));
assertThat(myList, not(containsInAnyOrder("apple", "banana")));
In the first assertion, we verify that myList contains “apple“, “banana“, and “cherry” in any order. Since all specified items are present in myList, the assertion passes.
The second assertion checks for “apple” and “banana” but omits “cherry“. Here, we expect not() to succeed because myList must exactly match the specified elements, including “cherry“, which is missing in this test data.
3.3. contains()
Similar to containsInAnyOrder(), the contains() matcher also requires the collection to have an exact count of elements but in the specified order:
assertThat(myList, contains("apple", "banana", "cherry"));
assertThat(myList, not(contains("apple", "banana")));
Similarly to containsInAnyOrder(), the second assertion expects not() matcher to succeed because the “cherry” element is missing in the test data.
4. Handling Duplicates
When dealing with collections that may contain duplicate elements, it’s essential to understand how hasItems(), contains(), and containsInAnyOrder() behave.
4.1. hasItems()
The hasItems() matcher doesn’t concern itself with the presence of duplicate elements. It simply checks for the presence of specified items, regardless of whether they’re duplicated:
List<String> myListWithDuplicate = Arrays.asList("apple", "banana", "cherry", "apple");
assertThat(myListWithDuplicate, hasItems("apple", "banana", "cherry"));
In this assertion, we verify that myListWithDuplicate contains “apple“, “banana“, and “cherry“. The hasItems() matcher checks for the presence of the specified items and ignores any duplicates. Since all specified items are present in the list, the assertion passes.
4.2. containsInAnyOrder()
Similarly, containsInAnyOrder() doesn’t enforce the ordering of elements. However, it ensures that all specified items are present, irrespective of duplicates:
assertThat(myList, containsInAnyOrder("apple", "banana", "cherry", "apple"));
assertThat(myListWithDuplicate, not(containsInAnyOrder("apple", "banana", "cherry")));
In this case, the “apple” duplicated element is missing from the second assertion test data, hence the not() matcher return succeeds.
4.3. contains()
On the other hand, the contains() matcher requires exact matching including the order and exact count of elements. If duplicates are present but not expected, the assertion fails:
assertThat(myList, not(contains("apple", "banana", "cherry")));
In this assertion, the “apple” duplicated element is missing from the test data, therefore the not() matcher return succeeds.
5. Summary
Let’s summarize the key differences among these matchers:
Matcher | Order | Exact Count | Handling Duplicates | Purpose |
---|---|---|---|---|
hasItems() | No | No | Ignores duplicates | Checks for the presence of specified elements, order does not matter |
containsInAnyOrder() | No | Yes | Requires exact elements | Checks for exact elements, order does not matter |
contains() | Yes | Yes | Requires exact sequence of elements | Checks for the exact sequence and exact elements |
6. Conclusion
In this article, we’ve explored the difference between hasItems(), contains() and containsInAnyOrder(). We use hasItems() when we only care that the collection contains at least the specified items regardless of their order. If the collection must contain all the specified items, but the order doesn’t matter, we can use containsInAnyOrder(). However, if the collection must contain the exact specified items in the same order they are provided, we should use contains().
As always, the source code for the examples is available over on GitHub.