Core Java

hasItems() vs. contains() vs. containsInAnyOrder() in Hamcrest

Hamcrest is a popular framework for writing matcher objects, allowing for more readable and flexible unit tests. Among its many matchers, hasItems(), contains(), and containsInAnyOrder() are often used to validate collections. Although they may seem similar at first glance, these matchers differ significantly in how they handle element ordering, exact element count, and duplicates. Let us delve into understanding hasItems(), contains() and containsInAnyOrder() in Hamcrest.

1. Introduction

When writing unit tests, particularly for collections, it’s essential to choose the right matcher to validate the contents of a collection. Hamcrest provides several useful methods for this purpose, including hasItems(), contains(), and containsInAnyOrder(). The table below summarizes the key differences between these methods:

MethodDescriptionElement OrderingExact Element CountHandling Duplicates
hasItems()Checks if the collection contains the specified elements, irrespective of order and count.Not importantNot requiredIgnores duplicates
contains()Asserts that the collection contains exactly the specified elements in the exact order.Strictly maintainedMust match exactlyConsiders duplicates
containsInAnyOrder()Verifies that the collection contains the specified elements in any order but with the exact count.Not importantMust match exactlyConsiders duplicates

2. Element Ordering

Element ordering refers to the sequence in which elements appear in a collection. Let’s explore how each matcher handles the order of elements.

2.1 hasItems()

The hasItems() matcher checks if the specified items are present in the collection, but it doesn’t consider the order of elements. It only requires that the elements exist in the collection.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange");
    assertThat(fruits, hasItems("Orange", "Apple"));
  }
}

In the above example, the test will pass as long as “Orange” and “Apple” are present in the list, irrespective of their order.

2.2 contains()

The contains() matcher checks if the collection contains the specified items in the exact order. It is strict about the sequence of elements.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange");
    assertThat(fruits, contains("Apple", "Banana", "Orange"));
  }
}

In this case, the test will pass only if the elements “Apple”, “Banana”, and “Orange” are present in that exact order in the list.

2.3 containsInAnyOrder()

The containsInAnyOrder() matcher checks if the collection contains the specified items but ignores the order. As long as all elements are present, the test will pass.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange");
    assertThat(fruits, containsInAnyOrder("Orange", "Apple", "Banana"));
  }
}

Here, the test will pass regardless of the order of the elements. It only checks that all specified items are present in the collection.

3. Exact Element Count

Exact element count refers to whether the matchers consider the number of occurrences of each element in the collection.

3.1 hasItems()

The hasItems() matcher doesn’t enforce the exact number of occurrences. It checks only for the presence of the specified items.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange", "Orange");
    assertThat(fruits, hasItems("Orange", "Apple"));
  }
}

The test will pass even though “Orange” appears twice in the list, as hasItems() does not require matching the exact count.

3.2 contains()

The contains() matcher checks both the presence and the exact count of elements in the specified order.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange", "Orange");
    assertThat(fruits, contains("Apple", "Banana", "Orange", "Orange"));
  }
}

The test will pass only if the list contains exactly “Apple”, “Banana”, “Orange”, and “Orange” in that order. The exact count matters here.

3.3 containsInAnyOrder()

Like contains(), the containsInAnyOrder() matcher also checks for the exact count of elements but ignores their order.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange", "Orange");
    assertThat(fruits, containsInAnyOrder("Orange", "Apple", "Orange", "Banana"));
  }
}

The test will pass only if all the specified elements are present in the list with the exact count, regardless of their order.

4. Handling Duplicates

Handling duplicates refers to how each matcher deals with repeated elements in the collection.

4.1 hasItems()

The hasItems() matcher ignores duplicates. It only checks if the specified items are present, regardless of how many times they appear.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange", "Orange");
    assertThat(fruits, hasItems("Orange", "Apple"));
  }
}

The test will pass as long as “Orange” and “Apple” are in the list, regardless of the number of “Orange” entries.

4.2 contains()

The contains() matcher is strict about duplicates and requires an exact match of the sequence with the correct count of elements.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange", "Orange");
    assertThat(fruits, contains("Apple", "Banana", "Orange", "Orange"));
  }
}

The test will pass only if the list has exactly two “Orange” elements in the specified order, reflecting the duplicates.

4.3 containsInAnyOrder()

The containsInAnyOrder() matcher also requires an exact match of the elements with the correct count but doesn’t care about their order.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

import java.util.Arrays;
import java.util.List;

public class HamcrestExample {
  public static void main(String[] args) {
    List < String > fruits = Arrays.asList("Apple", "Banana", "Orange", "Orange");
    assertThat(fruits, containsInAnyOrder("Orange", "Apple", "Orange", "Banana"));
  }
}

The test will pass as long as the list contains the correct number of each specified element, ignoring their order.

5. Conclusion

The methods hasItems(), contains(), and containsInAnyOrder() in Hamcrest offer powerful ways to assert collections in unit tests. Each method serves a specific purpose:

  • hasItems(): This method checks if the specified elements exist in the collection, regardless of order or count. It’s useful when the presence of elements is more important than their order or frequency.
  • contains(): This method ensures that the collection contains all specified elements in the exact order and number. It’s ideal when both order and count are crucial in the validation.
  • containsInAnyOrder(): This method verifies that the collection contains all the specified elements, in any order, but with the exact count. It’s perfect when the order doesn’t matter, but the exact elements and their frequency do.

Choosing the right method depends on what you need to validate in your tests. If you care only about the presence of elements, use hasItems(). If order and exact match are critical, contains() is the way to go. If the order is flexible but the exact elements and their count are important, containsInAnyOrder() is your best choice.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button