20

Is there a Hamcrest matcher which checks that the argument is neither an empty Collection nor null?

I guess I could always use

both(notNullValue()).and(not(hasSize(0))

but I was wondering whether there is a simpler way and I missed it.

DPM
  • 1,960
  • 3
  • 26
  • 49
jhyot
  • 3,733
  • 1
  • 27
  • 44
  • 3
    That looks pretty simple to me. Also, it's important that your tests express their intent with as much clarity as possible, and that code is very readable. – skaffman Dec 15 '14 at 21:41
  • I don't really know hamcrest, but logically you could check for `size >= 0`, if the API supports such calls. – mike Dec 15 '14 at 22:45
  • 1
    this question's title asks the opposite of this question's body. To answer the question's title: `assertThat( metadata, either( is( empty() ) ).or( is( nullValue() ) ) );` – Abdull Sep 09 '16 at 15:42
  • Not an exact match to your question, but you can `assertTrue(CollectionUtils.isNotEmpty(collectioin))`. `CollectionUtils` is an Apache Commons Lang class. – DwB Jan 09 '18 at 15:47

3 Answers3

13

You can combine the IsCollectionWithSize and the OrderingComparison matcher:

@Test
public void test() throws Exception {
    Collection<String> collection = ...;
    assertThat(collection, hasSize(greaterThan(0)));
}
  • For collection = null you get

    java.lang.AssertionError: 
    Expected: a collection with size a value greater than <0>
        but: was null
    
  • For collection = Collections.emptyList() you get

    java.lang.AssertionError: 
    Expected: a collection with size a value greater than <0>
        but: collection size <0> was equal to <0>
    
  • For collection = Collections.singletonList("Hello world") the test passes.

Edit:

Just noticed that the following approch is not working:

assertThat(collection, is(not(empty())));

The more i think about it the more i would recommend a slightly altered version of the statement written by the OP if you want to test explicitly for null.

assertThat(collection, both(not(empty())).and(notNullValue()));
eee
  • 3,241
  • 1
  • 17
  • 34
  • I accepted your answer because I think that both ways shown here, `hasSize(greaterThan(0))` and `both(not(empty())).and(notNullValue())` are a good way. – jhyot Dec 17 '14 at 12:09
  • Any reason why I get `1 expectation failed. JSON path images doesn't match. Expected: (an empty collection or null) Actual: null` when i try to check for empty collection or null with your code : `myResponse.body(myArrayAttr, either(empty()).or(nullValue()));` – TheBakker Jan 03 '18 at 15:11
2

As I posted in the comments, the logical equivalent of collection != null and size != 0 is size > 0, that implies the collection is not null. A simpler way to express size > 0 is there is an (arbitrary) element X in collection. Below a working code example.

import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.hamcrest.CoreMatchers.anything;

public class Main {

    public static void main(String[] args) {
        boolean result = hasItem(anything()).matches(null);
        System.out.println(result); // false for null

        result = hasItem(anything()).matches(Arrays.asList());
        System.out.println(result); // false for empty

        result = hasItem(anything()).matches(Arrays.asList(1, 2));
        System.out.println(result); // true for (non-null and) non-empty 
    }
}
mike
  • 4,929
  • 4
  • 40
  • 80
2

You are welcome to use Matchers:

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

assertThat(collection, anyOf(nullValue(), empty()));
Zon
  • 18,610
  • 7
  • 91
  • 99