9

Is there a shorter version of the following assert statement using standard Hamcrest matchers?

Collection<Element> collection = ...

assertThat(collection, is(anyOf(nullValue(Collection.class), 
     emptyCollectionOf(Element.class))));

I realize there is a way to create a custom matcher, was hoping that maybe there is already something in place that addresses this without any additional code change.

Altair7852
  • 1,226
  • 1
  • 14
  • 23

4 Answers4

12

There is no out-of-the-box solution, and worse, either() can't be used due to this bug. So the shortest way is this:

assertThat(collection, anyOf(nullValue(), empty()));
jihor
  • 2,478
  • 14
  • 28
2

One way to achieve this would be to create a custom Hamcrest matcher, which combines already available matches (like IsNull.nullValue() and IsEmptyCollection.empty()).

But generally speaking an assert should assert for one thing only. My opinion is that it's not a huge pain to have two matchers in succession and it's more readable later.

Also there's another preferred pattern - when returning a collection, prefer returning empty collection instead of null. The idea is to avoid unnecessary null checks.

hovanessyan
  • 30,580
  • 6
  • 55
  • 83
  • I agree in principle with your second statement. In practice though this combined situation comes up fairly often, so would be nice to have something like emptyOrNull() – Altair7852 Feb 21 '18 at 17:11
  • well different approaches are possible - you can always create a custom matcher (as suggested in other answers as well), or just wrap the two assertions in a utility method "nullOrEmpty(testTarget)" and call that in all places needed. In the end of the day - it's just test cases - if it tests the intended functionality - it's good to go. I really don't see a lot of benefit of squashing these two lines in a single assertion. – hovanessyan Feb 21 '18 at 21:24
1

The only way I can think of is to write your own Matcher

class EmptyOrNull extends BaseMatcher<Collection> {
    public boolean matches(Object o) {
        boolean result = o == null;
        if (o instanceof Collection) {
            result = ((Collection) o).isEmpty();
        }
        return result;
    }
    public String describeMismatch(Object item, Description description) {
        return "not null or empty!";
    }
    public static Matcher<Collection> emptyOrNull() { return new EmptyOrNull(); }
}

and then you can use the shorter version.

assertThat(collection, emptyOrNull());
daniu
  • 14,137
  • 4
  • 32
  • 53
0

Consider a simple imperative solution using Assert.fail.

if (collection != null && !collection.isEmpty()) {
    fail(collection.toString());
}
MikeFHay
  • 8,562
  • 4
  • 31
  • 52