Assert that collection "Contains at least one non-null element"

11,645

Solution 1

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

...

assertThat(collection, hasItem(notNullValue(Integer.class)));

Unfortunately, there is a bug in Java 1.6 that means you might have to split it onto 2 lines as described here if you are using 1.6:

Matcher<Iterable<? super String>> matcher = hasItem(notNullValue(Integer.class));
assertThat(collection, matcher);

EDIT Here is the FEST Assert example you asked for:

import static org.fest.assertions.api.Assertions.assertThat;
...
assertThat(collection).doesNotContainNull();

FEST requires only a single static import so you get full IDE auto completion.

Solution 2

I just ran into the same problem and solved it as follows.

The basic idea is that if the collection has only null elements, converted to a set it will contain just one element and it will be null. If not so, then the collection contains at least one non-null element.

I wrote a matcher, and tried it with this test:

import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static personal.CollectionOfNullsMatcher.collectionOfNulls;


public class SimpleTest {

    @Test
    public void should_check_collection_for_non_null_values() {
        Collection<String> testedCollection = new ArrayList<String>();
        testedCollection.add(null);

        assertThat(testedCollection, is(collectionOfNulls()));

        testedCollection.add("any");

        assertThat(testedCollection, is(not(collectionOfNulls())));
    }
}

class CollectionOfNullsMatcher extends TypeSafeMatcher<Collection> {

    @Override
    protected boolean matchesSafely(final Collection collection) {
        Set<Object> set = new HashSet<Object>(collection);
        return (set.size() == 1) && (set.toArray()[0] == null);
    }

    @Override
    public void describeTo(final Description description) {
        description.appendText("collection of nulls");
    }

    @Factory
    public static <T> Matcher<Collection> collectionOfNulls() {
        return new CollectionOfNullsMatcher();
    }
}

Of course, in a real project, the matcher should be placed together with its brothers :)

Hope it helps.

Solution 3

You're on the right track, chaining Matcher instances. You just need the hasItem matcher (like I've suggested here) instead of contains.

Creates a matcher for Iterables that only matches when a single pass over the examined Iterable yields at least one item that is matched by the specified itemMatcher. Whilst matching, the traversal of the examined Iterable will stop as soon as a matching item is found.

For example,

Collection<Integer> collection = new ArrayList<Integer>();
collection.add(null);

assertThat(collection, hasItem(is(not(nullValue()))));

will fail with

java.lang.AssertionError: 
Expected: a collection containing is not null
     but: was null
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
    at com.example.ExampleTest.should(ExampleTest.java:21)
    at [...]

whereas

Collection<Integer> collection = new ArrayList<Integer>();
collection.add(null);
collection.add("hey");
collection.add(null);

assertThat(collection, hasItem(is(not(nullValue()))));
// or shortened
assertThat(collection, hasItem(notNullValue()));

will succeed.

Solution 4

You can try the following:

public void shouldTestThis() {
        Collection<Integer> collection = new ArrayList<Integer>();
        collection.add(null);
        collection.removeAll(Collections.singleton(null)); // remove all "null" elements from collection
        assertThat(collection, is(not(empty())));
    }

As ajb notices, if you want to left your array unmodified, you should use an iterator and check each element until the end of the collection or a non null one.

Share:
11,645
Mike Rylander
Author by

Mike Rylander

Java Developer

Updated on June 11, 2022

Comments

  • Mike Rylander
    Mike Rylander over 1 year

    I want to verify that a collection contains at least one non-null element. I have tried is(not(empty())), however this passes in the test below.

    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.Collection;
    
    import static org.hamcrest.CoreMatchers.is;
    import static org.hamcrest.MatcherAssert.assertThat;
    import static org.hamcrest.Matchers.empty;
    import static org.hamcrest.Matchers.not;
    
    public class SandBoxTest {
        @Test
        public void shouldTestThis() {
            Collection<Integer> collection = new ArrayList<Integer>();
            collection.add(null);
    
            assertThat(collection, is(not(empty())));
        }
    }
    

    Is there an elegant/simple way to do this?

    Things That Don't Work

    @Test
    public void should(){
        Collection<String> collection = new ArrayList();
        collection.add("gfas");
        collection.add("asda");
        assertThat(collection, contains(notNullValue()));
    }
    
    java.lang.AssertionError: 
    Expected: iterable containing [not null]
         but: Not matched: "asda"
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
    
  • Sotirios Delimanolis
    Sotirios Delimanolis about 10 years
    The point is to check if it has null elements. You shouldn't remove them.
  • Julien
    Julien about 10 years
    The point is "to verify that a collection contains at least one non-null element."
  • ajb
    ajb about 10 years
    You could make this work without removing the null elements by making a copy of the collection (declare a temporary collection c and use c.addAll). But for that amount of work, you may as well just use an iterator.
  • Mike Rylander
    Mike Rylander about 10 years
    I will probably use this approach, but this would not work if the collection was immutable
  • Julien
    Julien about 10 years
    If the collection was immutable, you would have to use an iterator as @ajb notices
  • Mike Rylander
    Mike Rylander over 9 years
    Nice, a reusable matcher.