To compare nested objects we can use the usingRecursiveComparison()
method in AssertJ.
We can set up the nested objects with values we expect, invoke a method that would return the actual nested objects, and then use the usingRecursiveComparison()
method to compare the actual nested objects with the expected nested objects.
This is a very clean way to compare nested objects.
Also when we would add a new property to the nested objects our test would fail as we didn’t use that new property yet for our expected nested objects.
In the following example test we use the usingRecursiveComparison()
method to compare actual nested objects with the expected nested objects.
Our nested objects are of type Pirate
and Ship
.
// File: mrhaki/Ship.java package mrhaki; public record Ship(String name, String type, int crewSize) {}
// File: mrhaki/Pirate.java package mrhaki; public record Pirate(String name, String rank, Ship ship) {}
This is our class we want to test.
The class PirateShipCreator
creates the nested objects we want to write assertions for.
// File: mrhaki/PirateShipCreator.java package mrhaki; public class PirateShipCreator { public static Pirate createJackSparrow() { return new Pirate("Jack Sparrow", "Captain", createBlackPearl()); } public static Pirate createDavyJones() { return new Pirate("Davy Jones", "Captain", createFlyingDutchmain()); } private static Ship createBlackPearl() { return new Ship("Black Pearl", "Galleon", 100); } private static Ship createFlyingDutchmain() { return new Ship("Flying Dutchman", "Ghost ship", 199); } }
The test class PirateShipCreatorTest
uses the usingRecursiveComparison()
method to compare actual nested objects with the expected nested objects:
// File: mrhaki/PirateShipCreatorTest.java package mrhaki; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; public class PirateShipCreatorTest { @Test public void testPirateEquality() { // given Ship expectedShip = new Ship("Black Pearl", "Galleon", 100); Pirate expectedPirate = new Pirate("Jack Sparrow", "Captain", expectedShip); // when Pirate actualPirate = PirateShipCreator.createJackSparrow(); // then // assert equality using recursive comparison assertThat(actualPirate) .usingRecursiveComparison() .isEqualTo(expectedPirate); } }
If we want to ignore a property we can use the ignoringFields(String…)
method.
Or if we want to ignore properties of a certain type we can use the ignoringFieldsOfTypes(Class<?>…)
method. This can be very useful for properties that store dates we cannot setup properly in our tests.
Instead of ignoring fields we can also specify which fields we want to compare with the comparingOnlyFields(String…)
method.
And there is a comparingOnlyFieldsOfTypes(Class<?>…)
method to specify which fields of a certain type we want to compare.
In the following tests we use all four methods to ignore or include fields in our comparison.
// File: mrhaki/PirateShipCreatorTest.java package mrhaki; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; public class PirateShipCreatorTest { @Test public void testPirateEqualityIgnoringShipCrewSize() { // given Ship expectedShip = new Ship("Flying Dutchman", "Ghost Ship", 100); Pirate expectedPirate = new Pirate("Davy Jones", "Captain", expectedShip); // when Pirate actualPirate = PirateShipCreator.createDavyJones(); // then // assert equality using recursive comparison, ignoring crew size assertThat(actualPirate) .usingRecursiveComparison() .ignoringFields("ship.crewSize") .isEqualTo(expectedPirate); } @Test public void testPirateEqualityIgnoringIntegerFields() { // given Ship expectedShip = new Ship("Flying Dutchman", "Ghost Ship", 100); Pirate expectedPirate = new Pirate("Davy Jones", "Captain", expectedShip); // when Pirate actualPirate = PirateShipCreator.createDavyJones(); // then // assert equality using recursive comparison, ignoring integer fields assertThat(actualPirate) .usingRecursiveComparison() .ignoringFieldsOfType(Integer.class) .isEqualTo(expectedPirate); } @Test public void testPirateEqualityComparingSelectedFields() { // given Ship expectedShip = new Ship("Flying Dutchman", "Ghost Ship", 100); Pirate expectedPirate = new Pirate("Davy Jones", "Captain", expectedShip); // when Pirate actualPirate = PirateShipCreator.createDavyJones(); // then // assert equality using recursive comparison, comparing only selected fields assertThat(actualPirate) .usingRecursiveComparison() .comparingOnlyFields("name", "rank", "ship.name", "ship.type") .isEqualTo(expectedPirate); } @Test public void testPirateEqualityComparingSelectedTypeOfFields() { // given Ship expectedShip = new Ship("Flying Dutchman", "Ghost Ship", 100); Pirate expectedPirate = new Pirate("Davy Jones", "Captain", expectedShip); // when Pirate actualPirate = PirateShipCreator.createDavyJones(); // then // assert equality using recursive comparison, // comparing only fields of type String and Ship assertThat(actualPirate) .usingRecursiveComparison() .comparingOnlyFieldsOfTypes(String.class, Ship.class) .isEqualTo(expectedPirate); } }
Written with AssertJ 3.26.3.