Search code examples
javacollectionstestnghamcrest

Match empty collection with Hamcrest's hasItem()


How do I match an empty collection using TestNG and hasItem from Hamcrest? This is what I get as a result of one test.

java.lang.AssertionError: 
Expected: a collection containing email = null phone = null
got: <[]>

Here is my matcher class:

private static class MyPersonMatcher extends TypeSafeMatcher<Person> {
   private final String email;
   private final String phone;
      public ContactAgentUsageMatcher() {
   }
   public ContactAgentUsageMatcher(String email, String phone, Integer listingId) {
      this.email = email;
      this.phone = phone;
   }
   @Override
   public void describeTo(Description description) {
      description.appendText("email = ");
      description.appendValue(this.email);
      description.appendText(" phone = ");
      description.appendValue(this.phone);
   }
   @Override
   public boolean matchesSafely(ContactAgentUsage contactAgentUsage) {
      if ((this.email == null) && (this.phone == null)) {
         return true;
      }
      else {
         return ObjectUtils.equals(this.email, contactAgentUsage.getEmail())
             && ObjectUtils.equals(this.phone, contactAgentUsage.getPhone());
      }
   }
}

The test that fails is

assertThat(argument.getAllValues(), hasItem(expectedMatcher));

where expectedMatcher is provided by data provider. I am not sure what to pass to match this "empty collection" as a result. I am passing default constructor but I know this doesn't work because it creates collection with null members.

This is part of my data provider:

{ new ContactAgentUsageMatcher()}

Solution

  • Your custom matcher will match any existing Person when the configured email and name are both set to null. However, the collection doesn't contain any Persons to match against. Hamcrest's hasItem(matcher) fails the test in this case and is the wrong matcher to use for empty collections.

    Here are two workarounds:

    1. Change the data provider and tests to take the full matcher including hasItem. For the above case you would pass emptyIterable. The downside is that you'll need to tell the Java compiler which generic type it should use which will clutter the tests.

    2. Create a second test to handle the data sets that produce an empty collection.