How do I check that no value is null after calling extracting on a list of objects?

433 Views Asked by At

Using AssertJ in a unit test, I want to extract several properties of a custom object from a list of such objects via extracting and check if they are all non-null.

For example, assuming I want to extract fieldA and fieldB of MyObject:

import static from org.assertj.core.api.Assertions.assertThat;

List<MyObject> theList = ...; 
assertThat(theList).extracting("fieldA", "fieldB")).isNotNull();

I am having trouble figuring out what is being checked.

Is isNotNull checking that:

  1. the iterable returned by extracting is not null?
  2. no tuples in the list are null?
  3. every value in every tuple is not null?
2

There are 2 best solutions below

2
Stefano Cordio On BEST ANSWER

Following your example:

assertThat(theList).extracting("fieldA", "fieldB").isNotNull();

isNotNull only checks that the Iterable of tuples returned by extracting is not null.

flatExtracting + doesNotContainNull

To check that none of the extracted values are null, you can use flatExtracting and doesNotContainNull:

assertThat(theList).flatExtracting("fieldA", "fieldB").doesNotContainNull();

which yields a message like the following in case of failures:

java.lang.AssertionError: 
Expecting actual:
  ["value1", "value2", null, "value4"]
not to contain null elements

Due to the flattened nature of the solution, there is no indication of which object caused the failure but can be identified by counting the pairs in the displayed actual.

extracting + noneMatch

The complexity can be increased for clearer error messages:

assertThat(theList).extracting("fieldA", "fieldB").noneMatch(tuple -> tuple.toList().contains(null));

which yields in case of failure:

java.lang.AssertionError: [Extracted: fieldA, fieldB] 
Expecting no elements of:
  [("value1", "value2"), (null, "value4")]
to match given predicate but this element did:
  (null, "value4")

extracting + allSatisfy + doesNotContainNull

Another option for clearer error messages:

assertThat(theList).extracting("fieldA", "fieldB").allSatisfy(tuple -> assertThat(tuple.toList()).doesNotContainNull());

which yields in case of failure:

java.lang.AssertionError: [Extracted: fieldA, fieldB] 
Expecting all elements of:
  [("value1", "value2"), (null, "value4")]
to satisfy given requirements, but these elements did not:

(null, "value4")
error: 
Expecting actual:
  [null, "value4"]
not to contain null elements
3
Shila Mosammami On

When you use AssertJ's extracting method followed by isNotNull(), it checks if the list of Objects itself is not null, not each individual extracted value.

Given your example:

assertThat(theList).extracting("fieldA", "fieldB").isNotNull();

Here's what it checks:

  1. For every MyObject in theList, it extracts values of fieldA and fieldB.
  2. The values are combined into an object (for two fields, it'll be a pair).
  3. The isNotNull() method then asserts that the list of Object itself is not null.

The following code can ensure every value in every object is not null. If any null values are present, the assertion will fail:

    import static org.assertj.core.api.Assertions.assertThat;
    import java.util.Arrays;
    import java.util.List;
public class test {
     static class MyObject {
            String fieldA;
            String fieldB;

            public MyObject(String fieldA, String fieldB) {
                this.fieldA = fieldA;
                this.fieldB = fieldB;
            }

            // Getter methods for fieldA and fieldB
            public String getFieldA() {
                return fieldA;
            }

            public String getFieldB() {
                return fieldB;
            }
        }

        public static void main(String[] args) {
            List<MyObject> theList = Arrays.asList(
                new MyObject("valueA1", "valueB1"),
                new MyObject("valueA2", "valueB2"),
                new MyObject("valueA3", "valueB3"),
                new MyObject(null, "valueB4"),  
                new MyObject("valueA5", null)  
            );

            try {
                assertThat(theList).extracting(MyObject::getFieldA).doesNotContainNull();
                System.out.println("Assertion for fieldA passed.");
            } catch (AssertionError e) {
                System.out.println("Assertion for fieldA failed: " + e.getMessage());
            }

            try {
                assertThat(theList).extracting(MyObject::getFieldB).doesNotContainNull();
                System.out.println("Assertion for fieldB passed.");
            } catch (AssertionError e) {
                System.out.println("Assertion for fieldB failed: " + e.getMessage());
            }
        }
}

As you see, this way you can even determine which element caused a failure: fieldA or fieldB.

enter image description here