Choosing the Right Matcher: HasItems vs Contains vs ContainsInAnyOrder

- Published on
Choosing the Right Matcher: HasItems vs Contains vs ContainsInAnyOrder
When working with testing frameworks in Java, especially in the realm of unit testing with libraries like Hamcrest or Mockito, properly asserting the correctness of your code is crucial. Three common matchers that often cause confusion among developers are hasItems
, contains
, and containsInAnyOrder
. In this blog post, we'll explore each of these matchers, discuss their differences, and provide practical examples to help you choose the right matcher for your specific situation.
Understanding the Matchers
1. HasItems
hasItems
is a matcher that checks whether a collection contains a specific set of elements, regardless of their order. It is particularly useful when you want to ensure that required elements are present in the collection but the order does not matter.
Example:
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertThat;
import java.util.List;
import org.junit.Test;
public class MatcherExample {
@Test
public void testHasItems() {
List<String> actualList = List.of("apple", "banana", "orange");
assertThat(actualList, hasItems("banana", "orange"));
}
}
Why Use hasItems
?
Use hasItems
when you care only about the presence of elements and not their order. This flexibility makes it perfect for scenarios where the element order is irrelevant.
2. Contains
contains
is a matcher that checks whether a collection contains a specific sequence of elements in the same order. This matcher is instrumental when the sequence is crucial to the integrity of the output.
Example:
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertThat;
import java.util.List;
import org.junit.Test;
public class MatcherExample {
@Test
public void testContains() {
List<String> actualList = List.of("java", "python", "javascript");
assertThat(actualList, contains("java", "python", "javascript"));
}
}
Why Use contains
?
Use contains
when the order of elements is significant. This matcher verifies not only the presence of each element but also the expected sequence.
3. ContainsInAnyOrder
containsInAnyOrder
is a matcher that checks whether a collection contains a specific set of elements, allowing for any order. It is useful when the element count and presence are important, but the sequence does not matter.
Example:
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
import java.util.List;
import org.junit.Test;
public class MatcherExample {
@Test
public void testContainsInAnyOrder() {
List<String> actualList = List.of("car", "bike", "bus");
assertThat(actualList, containsInAnyOrder("bus", "car", "bike"));
}
}
Why Use containsInAnyOrder
?
Use containsInAnyOrder
when the presence of every specified element and their count is essential, but the order in which they appear is not. It's perfect for situations like testing unordered sets or bags.
Comparison of Matchers
To summarize, here's a quick comparison of the three matchers:
| Matcher | Order Matter? | Presence Check | Use Case |
|-----------------------|----------------|----------------|------------------------------------------------|
| hasItems
| No | Yes | Checking for the presence of elements |
| contains
| Yes | Yes | Checking for a specific ordered sequence |
| containsInAnyOrder
| No | Yes | Checking for presence and counting, order agnostic |
When to Use Each Matcher
Understanding how to choose the right matcher depends on the specific assertions you are making in your unit tests:
-
Use
hasItems
when you want to perform a simple existence check across elements and their order does not matter. This is often used in tests with collections where the order does not impact functionality. -
Use
contains
when you need to validate the exact order of a list. This is common in scenarios where the output must match a predefined sequence, such as in certain sorting algorithms or pipeline processes. -
Use
containsInAnyOrder
when verifying collections likeSet
s or other unordered collections where the order doesn't matter, but you still want to ensure all required elements are present.
The Closing Argument
In unit testing, choosing the right matcher can enhance the clarity and effectiveness of your assertions. Understanding the distinctions among hasItems
, contains
, and containsInAnyOrder
can significantly reduce confusion and improve your testing strategy.
For further reading on unit testing in Java, consider the following resources:
Choosing the appropriate matcher according to the context of your tests can make your unit tests both clearer and more robust, thereby enhancing the overall quality and maintainability of your codebase. Happy testing!