AssertJ: For a Pojo how to check each nested Property/Field in one chained sentence
Asked Answered
D

1

40

Having a POJO such as:

public class ClientWebRequest {

    private URI uri;
    private HttpMethod httpMethod;

    private final Header header;
    private final Body body;


    public ClientWebRequest(){
        header = new Header();
        body = new Body();
    }

    //getters and setters
}

About JUnit working with AssertJ the following is valid, the @Test method pass:

assertThat(clientWebRequest).isNotNull();
assertThat(clientWebRequest.getHeader()).isNotNull();
assertThat(clientWebRequest.getHeader().getAccept()).isNotNull();
assertThat(clientWebRequest.getHeader().getAcceptLanguage()).isNull();
assertThat(clientWebRequest.getHeader().getContentType()).isNull();
assertThat(clientWebRequest.getBody()).isNotNull();
assertThat(clientWebRequest.getBody().getBody()).isNull();

Even when it works, is verbose in some way.

I want to know if is possible rewrite all the above in just one sentence, checking each nested property/field. Thus I have tried for example the following:

assertThat(clientWebRequest.getHeader()).isNotNull()
        .hasFieldOrProperty("accept").isNotNull()
        .hasFieldOrProperty("acceptLanguage").isNull();

But fails with the following error message:

org.junit.ComparisonFailure: expected:<null> 
but was:<Header [accept=[application/json;charset=UTF-8], acceptLanguage=null, contentType=null]>
        at

My main goal is workaround with isNotNull and isNull for each property/field of the POJO

Alpha: Thanks to Joel's suggestion the following works now:

assertThat(clientWebRequest).isNotNull()
                            .extracting("header.accept")
                            .doesNotContainNull();

assertThat(clientWebRequest).isNotNull()
        .extracting("header.acceptLanguage", "header.contentType")
       .containsNull();

From above (two blocks) If I try the following (one block):

assertThat(clientWebRequest).isNotNull()
                            .extracting("header.accept")
                            .doesNotContainNull();
       .extracting("header.acceptLanguage", "header.contentType")
       .containsNull();

It fails. Just curious if is possible apply one block.

Decalcomania answered 25/12, 2017 at 15:33 Comment(0)
H
70

I think the best way is to extract all the properties/fields and then checks it does not contain null.

Example:

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);

// support nested properties: 
assertThat(frodo).extracting("name", "age", "race.name")
                 .doesNotContainNull()
                 .containsExactly("Frodo", 33, "Hobbit");

Note that you can also use lambdas to extract values from the object under test.

assertThat(frodo).extracting(TolkienCharacter::getName,
                             character -> character.age,
                             character -> character.getRace().getName())
                 .containsExactly("Frodo", 33, "Hobbit");
Hatshepsut answered 26/12, 2017 at 7:14 Comment(5)
Thanks, please see the Alpha section added. Not sure if one block is possible.Decalcomania
That won't work because after applying extracting you end up performing assertions on the collection of values corresponding to the extracted properties. If you use extracting again it will try to extract properties from each elements of the previous collection of values.Hatshepsut
what will happen if character.getRace() is null, wouldn't the test case blow up with NullPointerException?Saipan
For Kotlin users the last line of the first example will look like: .containsExactly(Tuple("Frodo", 33, "Hobbit"))Cerement
From AssertJ 3.12.0 you can use assertThat(frodo).usingRecursiveComparison().isEqualTo(expectedFrolo), see https://mcmap.net/q/327398/-how-to-compare-recursively-ignoring-given-fields-using-assertjElbaelbart

© 2022 - 2024 — McMap. All rights reserved.