Class RecursiveComparisonAssert<SELF extends RecursiveComparisonAssert<SELF>>
- java.lang.Object
-
- org.assertj.core.api.AbstractAssert<SELF,Object>
-
- org.assertj.core.api.RecursiveComparisonAssert<SELF>
-
- All Implemented Interfaces:
Assert<SELF,Object>
,Descriptable<SELF>
,ExtensionPoints<SELF,Object>
public class RecursiveComparisonAssert<SELF extends RecursiveComparisonAssert<SELF>> extends AbstractAssert<SELF,Object>
-
-
Field Summary
Fields Modifier and Type Field Description private RecursiveComparisonConfiguration
recursiveComparisonConfiguration
private RecursiveComparisonDifferenceCalculator
recursiveComparisonDifferenceCalculator
-
Fields inherited from class org.assertj.core.api.AbstractAssert
actual, assertionErrorCreator, conditions, info, myself, objects, throwUnsupportedExceptionOnEquals
-
-
Constructor Summary
Constructors Constructor Description RecursiveComparisonAssert(Object actual, RecursiveComparisonConfiguration recursiveComparisonConfiguration)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description private List<ComparisonDifference>
determineDifferencesWith(Object expected)
RecursiveComparisonConfiguration
getRecursiveComparisonConfiguration()
Returns theRecursiveComparisonConfiguration
currently used.SELF
ignoringActualEmptyOptionalFields()
Makes the recursive comparison to ignore all actual empty optional fields (includingOptional
,OptionalInt
,OptionalLong
andOptionalDouble
), note that the expected object empty optional fields are not ignored, this only applies to actual's fields.SELF
ignoringActualNullFields()
Makes the recursive comparison to ignore all actual null fields (but note that the expected object null fields are used in the comparison).SELF
ignoringAllOverriddenEquals()
This method instructs the recursive comparison to compare recursively all fields including the one whose type have overridden equals, except fields with java types (at some point we need to compare something!).SELF
ignoringCollectionOrder()
Makes the recursive comparison to ignore collection order in all fields in the object under test.SELF
ignoringCollectionOrderInFields(String... fieldsToIgnoreCollectionOrder)
Makes the recursive comparison to ignore collection order in the object under test specified fields.SELF
ignoringCollectionOrderInFieldsMatchingRegexes(String... regexes)
Makes the recursive comparison to ignore collection order in the object under test fields matching the specified regexes.SELF
ignoringExpectedNullFields()
Makes the recursive comparison to ignore all expected null fields.SELF
ignoringFields(String... fieldNamesToIgnore)
Makes the recursive comparison to ignore the given object under test fields.SELF
ignoringFieldsMatchingRegexes(String... regexes)
Makes the recursive comparison to ignore the object under test fields whose name matche the given regexes.RecursiveComparisonAssert<?>
ignoringFieldsOfTypes(Class<?>... typesToIgnore)
Makes the recursive comparison to ignore the object under test fields of the given types.SELF
ignoringOverriddenEqualsForFields(String... fields)
In case you have instructed the recursive to use overriddenequals
withusingOverriddenEquals()
, this method allows to ignore overriddenequals
for the given fields (it adds them to the already registered ones).SELF
ignoringOverriddenEqualsForFieldsMatchingRegexes(String... regexes)
In case you have instructed the recursive to use overriddenequals
withusingOverriddenEquals()
, this method allows to force a recursive comparison for the fields matching the given regexes (it adds them to the already registered ones).SELF
ignoringOverriddenEqualsForTypes(Class<?>... types)
By default the recursive comparison uses overriddenequals
methods to compare fields, this method allows to force a recursive comparison for all fields of the given types (it adds them to the already registered ones).SELF
isEqualTo(Object expected)
Asserts that the object under test (actual) is equal to the given object when compared field by field recursively (including inherited fields are included in the comparison).SELF
isNotEqualTo(Object other)
Asserts that actual object is not equal to the given object based on a recursive property/field by property/field comparison (including inherited ones).private void
registerComparatorForType(Map.Entry<Class<?>,Comparator<?>> entry)
(package private) void
setRecursiveComparisonConfiguration(RecursiveComparisonConfiguration recursiveComparisonConfiguration)
SELF
usingOverriddenEquals()
By default the recursive comparison compare recursively all fields including the ones whose type have overridden equals except fields with java types (at some point we need to compare something!).SELF
withComparatorForFields(Comparator<?> comparator, String... fieldLocations)
Allows to register a comparator to compare fields with the given locations.<T> SELF
withComparatorForType(Comparator<? super T> comparator, Class<T> type)
Allows to register a comparator to compare the fields with the given type.SELF
withEqualsForFields(BiPredicate<?,?> equals, String... fieldLocations)
Allows to register aBiPredicate
to compare fields with the given locations.<T> SELF
withEqualsForType(BiPredicate<? super T,? super T> equals, Class<T> type)
Allows to register aBiPredicate
to compare the fields with the given type.SELF
withStrictTypeChecking()
Makes the recursive comparison to check that actual's type is compatible with expected's type (and do the same for each field).(package private) SELF
withTypeComparators(TypeComparators typeComparators)
-
Methods inherited from class org.assertj.core.api.AbstractAssert
asInstanceOf, asList, assertionError, asString, describedAs, descriptionText, doesNotHave, doesNotHaveSameClassAs, doesNotHaveSameHashCodeAs, doesNotHaveToString, equals, extracting, extracting, failure, failureWithActualExpected, failWithActualExpectedAndMessage, failWithMessage, getWritableAssertionInfo, has, hashCode, hasSameClassAs, hasSameHashCodeAs, hasToString, inBinary, inHexadecimal, is, isElementOfCustomAssert, isExactlyInstanceOf, isIn, isIn, isInstanceOf, isInstanceOfAny, isInstanceOfSatisfying, isNot, isNotExactlyInstanceOf, isNotIn, isNotIn, isNotInstanceOf, isNotInstanceOfAny, isNotNull, isNotOfAnyClassIn, isNotSameAs, isNull, isOfAnyClassIn, isSameAs, matches, matches, newListAssertInstance, overridingErrorMessage, overridingErrorMessage, satisfies, satisfies, satisfiesAnyOf, satisfiesAnyOf, satisfiesAnyOf, setCustomRepresentation, setDescriptionConsumer, setPrintAssertionsDescription, throwAssertionError, usingComparator, usingComparator, usingDefaultComparator, usingRecursiveComparison, usingRecursiveComparison, withAssertionState, withFailMessage, withFailMessage, withRepresentation, withThreadDumpOnError
-
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, toString, wait, wait, wait
-
Methods inherited from interface org.assertj.core.api.Descriptable
as, as, as, describedAs
-
-
-
-
Field Detail
-
recursiveComparisonConfiguration
private RecursiveComparisonConfiguration recursiveComparisonConfiguration
-
recursiveComparisonDifferenceCalculator
private RecursiveComparisonDifferenceCalculator recursiveComparisonDifferenceCalculator
-
-
Constructor Detail
-
RecursiveComparisonAssert
public RecursiveComparisonAssert(Object actual, RecursiveComparisonConfiguration recursiveComparisonConfiguration)
-
-
Method Detail
-
setRecursiveComparisonConfiguration
void setRecursiveComparisonConfiguration(RecursiveComparisonConfiguration recursiveComparisonConfiguration)
-
isEqualTo
public SELF isEqualTo(Object expected)
Asserts that the object under test (actual) is equal to the given object when compared field by field recursively (including inherited fields are included in the comparison). If the comparison fails it will report all the differences found and which effectiveRecursiveComparisonConfiguration
was used to help users understand the failure.This is typically useful when actual's
equals
was not overridden.The comparison is not symmetrical since it is limited to actual's fields, the algorithm gather all actual's fields and then compare them to the corresponding expected's fields.
It is then possible for the expected object to have more fields than actual which is handy when comparing a base type to a subtype.Strict/lenient recursive comparison
By default the objects to compare can be of different types but must have the same properties/fields. For example if object under test has a
work
field of typeAddress
, the expected object to compare the object under test to must also have one but it can of a different type likeAddressDto
.It is possible to enforce strict type checking by calling
withStrictTypeChecking()
and make the comparison fail whenever the compared objects or their fields are not compatible.
Compatible means that the expected object/field types are the same or a subtype of actual/field types, for example if actual is anAnimal
and expected aDog
, they will be compared field by field in strict type checking mode.Ignoring null fields in the recursive comparison
When an object is partially populated, it can still be interesting to see if its populated values are correct against a fully populated object.
This possible by calling
ignoringActualNullFields()
beforeisEqualTo
but bear in mind that only actual null fields are ignored, said otherwise the expected object null fields are used in the comparison.Recursive comparison use of overridden
equals
methodsBy default the recursive comparison is not applied on fields whose classes have overridden the
equals
method, concretely it meansequals
is used to compare these fields instead of keeping on applying the recursive comparison. The rationale is that if a class has redefinedequals
then it should be used to compare instances unless having a good reason.It is possible though to change this behavior and force recursive comparison by calling any of these methods (but before calling
isEqualTo
otherwise this has no effect!):-
ignoringOverriddenEqualsForTypes(Class...)
Any fields of these classes are compared recursively -
ignoringOverriddenEqualsForFields(String...)
Any given fields are compared recursively -
ignoringOverriddenEqualsForFieldsMatchingRegexes(String...)
Any fields matching one of these regexes are compared recursively -
ignoringAllOverriddenEquals()
except for java types, all fields are compared field by field recursively.
The recursive comparison handles cycles.
Comparator used in the recursive comparison
By default
floats
are compared with a precision of 1.0E-6 anddoubles
with 1.0E-15.You can specify a custom comparator or equals BiPredicate per (nested) fields or type with the methods below (but before calling
isEqualTo
otherwise this has no effect!):-
withEqualsForType(BiPredicate, Class)
for a given type -
withComparatorForType(Comparator, Class)
for a given type -
withComparatorForFields(Comparator, String...)
for one or multiple fields -
withComparatorForFields(Comparator, String...)
for one or multiple fields
Note that field comparators always take precedence over type comparators.
Example
Here is a basic example with a default
RecursiveComparisonConfiguration
, you can find other examples for each of the method changing the recursive comparison behavior likeignoringFields(String...)
.public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); Date ownedSince; } public static class Address { int number; String street; } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.ownedSince = new Date(123); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.80); sherlock2.home.ownedSince = new Date(123); sherlock2.home.address.street = "Baker Street"; sherlock2.home.address.number = 221; // assertion succeeds as the data of both objects are the same. assertThat(sherlock).usingRecursiveComparison() .isEqualTo(sherlock2);
- Specified by:
isEqualTo
in interfaceAssert<SELF extends RecursiveComparisonAssert<SELF>,Object>
- Overrides:
isEqualTo
in classAbstractAssert<SELF extends RecursiveComparisonAssert<SELF>,Object>
- Parameters:
expected
- the object to compareactual
to.- Returns:
this
assertion object.- Throws:
AssertionError
- if the actual object isnull
.AssertionError
- if the actual and the given objects are not deeply equal property/field by property/field.IntrospectionError
- if one property/field to compare can not be found.
-
-
isNotEqualTo
public SELF isNotEqualTo(Object other)
Asserts that actual object is not equal to the given object based on a recursive property/field by property/field comparison (including inherited ones).This is typically useful when actual's
equals
was not overridden.The comparison is not symmetrical since it is limited to actual's fields, the algorithm gather all actual's fields and then compare them to the corresponding expected's fields.
It is then possible for the expected object to have more fields than actual which is handy when comparing a base type to a subtype.This method is based on
isEqualTo(Object)
, you can check out more usages in that method.Example
// equals not overridden in TolkienCharacter TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT); TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT); TolkienCharacter youngFrodo = new TolkienCharacter("Frodo", 22, HOBBIT); // Pass as equals compares object references assertThat(frodo).isNotEqualTo(frodoClone); // Fail as frodo and frodoClone are equals when doing a field by field comparison. assertThat(frodo).usingRecursiveComparison() .isNotEqualTo(frodoClone); // Pass as one the age fields differ between frodo and youngFrodo. assertThat(frodo).usingRecursiveComparison() .isNotEqualTo(youngFrodo);
- Specified by:
isNotEqualTo
in interfaceAssert<SELF extends RecursiveComparisonAssert<SELF>,Object>
- Overrides:
isNotEqualTo
in classAbstractAssert<SELF extends RecursiveComparisonAssert<SELF>,Object>
- Parameters:
other
- the object to compareactual
to.- Returns:
this
assertions object- Throws:
AssertionError
- if the actual object and the given objects are bothnull
.AssertionError
- if the actual and the given objects are equals property/field by property/field recursively.- Since:
- 3.17.0
- See Also:
isEqualTo(Object)
-
ignoringActualNullFields
public SELF ignoringActualNullFields()
Makes the recursive comparison to ignore all actual null fields (but note that the expected object null fields are used in the comparison).Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; } Person noName = new Person(null, 1.80); noName.home.address.street = null; noName.home.address.number = 221; Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; // assertion succeeds as name and home.address.street fields are ignored in the comparison assertThat(noName).usingRecursiveComparison() .ignoringActualNullFields() .isEqualTo(sherlock); // assertion fails as name and home.address.street fields are populated for sherlock but not for noName. assertThat(sherlock).usingRecursiveComparison() .ignoringActualNullFields() .isEqualTo(noName);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringActualEmptyOptionalFields
public SELF ignoringActualEmptyOptionalFields()
Makes the recursive comparison to ignore all actual empty optional fields (includingOptional
,OptionalInt
,OptionalLong
andOptionalDouble
), note that the expected object empty optional fields are not ignored, this only applies to actual's fields.Example:
public class Person { String name; OptionalInt age; OptionalLong id; OptionalDouble height; Home home = new Home(); } public class Home { String address; Optional<String> phone; } Person homerWithoutDetails = new Person("Homer Simpson"); homerWithoutDetails.home.address.street = "Evergreen Terrace"; homerWithoutDetails.home.address.number = 742; homerWithoutDetails.home.phone = Optional.empty(); homerWithoutDetails.age = OptionalInt.empty(); homerWithoutDetails.id = OptionalLong.empty(); homerWithoutDetails.height = OptionalDouble.empty(); Person homerWithDetails = new Person("Homer Simpson"); homerWithDetails.home.address.street = "Evergreen Terrace"; homerWithDetails.home.address.number = 742; homerWithDetails.home.phone = Optional.of("(939) 555-0113"); homerWithDetails.age = OptionalInt.of(39); homerWithDetails.id = OptionalLong.of(123456); homerWithDetails.height = OptionalDouble.of(1.83); // assertion succeeds as phone is ignored in the comparison assertThat(homerWithoutDetails).usingRecursiveComparison() .ignoringActualEmptyOptionalFields() .isEqualTo(homerWithDetails); // assertion fails as phone, age, id and height are not ignored and are populated for homerWithDetails but not for homerWithoutDetails. assertThat(homerWithDetails).usingRecursiveComparison() .ignoringActualEmptyOptionalFields() .isEqualTo(homerWithoutDetails);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringExpectedNullFields
public SELF ignoringExpectedNullFields()
Makes the recursive comparison to ignore all expected null fields.Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person noName = new Person(null, 1.80); noName.home.address.street = null; noName.home.address.number = 221; // assertion succeeds as name and home.address.street fields are ignored in the comparison assertThat(sherlock).usingRecursiveComparison() .ignoringExpectedNullFields() .isEqualTo(noName); // assertion fails as name and home.address.street fields are populated for sherlock but not for noName. assertThat(noName).usingRecursiveComparison() .ignoringExpectedNullFields() .isEqualTo(sherlock);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringFields
public SELF ignoringFields(String... fieldNamesToIgnore)
Makes the recursive comparison to ignore the given object under test fields. Nested fields can be specified like this:home.address.street
.The given fieldNamesToIgnore are matched agains field names, not field values.
Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person noName = new Person(null, 1.80); noName.home.address.street = null; noName.home.address.number = 221; // assertion succeeds as name and home.address.street fields are ignored in the comparison assertThat(sherlock).usingRecursiveComparison() .ignoringFields("name", "home.address.street") .isEqualTo(noName); // assertion fails as home.address.street fields differ and is not ignored. assertThat(sherlock).usingRecursiveComparison() .ignoringFields("name") .isEqualTo(noName);
- Parameters:
fieldNamesToIgnore
- the field names of the object under test to ignore in the comparison.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringFieldsMatchingRegexes
public SELF ignoringFieldsMatchingRegexes(String... regexes)
Makes the recursive comparison to ignore the object under test fields whose name matche the given regexes.Nested fields can be specified by using dots like this:
home\.address\.street
(\
is used to escape dots since they have a special meaning in regexes).Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person noName = new Person(null, 1.80); noName.home.address.street = "Butcher Street"; noName.home.address.number = 222; // assertion succeeds as name and all home fields are ignored in the comparison assertThat(sherlock).usingRecursiveComparison() .ignoringFieldsMatchingRegexes("n.me", "home.*") .isEqualTo(noName); // although home fields are ignored, assertion fails as name fields differ. assertThat(sherlock).usingRecursiveComparison() .ignoringFieldsMatchingRegexes("home.*") .isEqualTo(noName);
- Parameters:
regexes
- regexes used to ignore fields in the comparison.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringFieldsOfTypes
public RecursiveComparisonAssert<?> ignoringFieldsOfTypes(Class<?>... typesToIgnore)
Makes the recursive comparison to ignore the object under test fields of the given types. The fields are ignored if their types exactly match one of the ignored types, for example if a field is a subtype of an ignored type it is not ignored.If some object under test fields are null it is not possible to evaluate their types unless in
strictTypeChecking mode
, in that case the corresponding expected field's type is evaluated instead but if strictTypeChecking mode is disabled then null fields are not ignored.Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.90); sherlock2.home.address.street = "Butcher Street"; sherlock2.home.address.number = 221; // assertion succeeds as we ignore Address and height assertThat(sherlock).usingRecursiveComparison() .ignoringFieldsOfTypes(double.class, Address.class) .isEqualTo(sherlock2); // now this assertion fails as expected since the home.address.street fields and height differ assertThat(sherlock).usingRecursiveComparison() .isEqualTo(sherlock2);
- Parameters:
typesToIgnore
- the types we want to ignore in the object under test fields.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringAllOverriddenEquals
public SELF ignoringAllOverriddenEquals()
This method instructs the recursive comparison to compare recursively all fields including the one whose type have overridden equals, except fields with java types (at some point we need to compare something!).Since 3.17.0 this is the default behavior for recursive comparisons, to revert to the previous behavior call
usingOverriddenEquals()
.Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; // only compares number, ouch! @Override public boolean equals(final Object other) { if (!(other instanceof Address)) return false; Address castOther = (Address) other; return Objects.equals(number, castOther.number); } } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.80); sherlock2.home.address.street = "Butcher Street"; sherlock2.home.address.number = 221; // Assertion succeeds because: // - overridden equals are used // - Address has overridden equals and does not compare street fields. assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .isEqualTo(sherlock2); // To avoid using Address overridden equals, don't call usingOverriddenEquals() or call ignoringAllOverriddenEquals() // (calling ignoringAllOverriddenEquals() is actually not required as this is the default behavior). // This assertion fails as it will compare home.address.street fields which differ assertThat(sherlock).usingRecursiveComparison() //.ignoringAllOverriddenEquals() // not needed as this is the default .isEqualTo(sherlock2);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
usingOverriddenEquals
public SELF usingOverriddenEquals()
By default the recursive comparison compare recursively all fields including the ones whose type have overridden equals except fields with java types (at some point we need to compare something!).This method instructs the recursive comparison to use overridden equals.
Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; // only compares number! @Override public boolean equals(final Object other) { if (!(other instanceof Address)) return false; Address castOther = (Address) other; return Objects.equals(number, castOther.number); } } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.80); sherlock2.home.address.street = "Butcher Street"; sherlock2.home.address.number = 221; // assertion succeeds because Address equals does not compare street fields. assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .isEqualTo(sherlock2); // Assertion fails because: // - Address equals is not used. // - street fields are compared and differ. assertThat(sherlock).usingRecursiveComparison() .isEqualTo(sherlock2);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods. - Since:
- 3.17.0
-
ignoringOverriddenEqualsForFields
public SELF ignoringOverriddenEqualsForFields(String... fields)
In case you have instructed the recursive to use overriddenequals
withusingOverriddenEquals()
, this method allows to ignore overriddenequals
for the given fields (it adds them to the already registered ones).Since 3.17.0 all overridden
equals
so this method is only relevant if you have calledusingOverriddenEquals()
before.Nested fields can be specified by using dots like this:
home.address.street
Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; // only compares number @Override public boolean equals(final Object other) { if (!(other instanceof Address)) return false; Address castOther = (Address) other; return Objects.equals(number, castOther.number); } } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.80); sherlock2.home.address.street = "Butcher Street"; sherlock2.home.address.number = 221; // Assertion succeeds because: // - overridden equals are used // - Address has overridden equals and does not compare street fields. assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .isEqualTo(sherlock2); // ignoringOverriddenEqualsForFields force a recursive comparison on the given field // Assertion fails because: // - Address equals is not used. // - street fields are compared and differ. assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .ignoringOverriddenEqualsForFields("home.address") .isEqualTo(sherlock2);
- Parameters:
fields
- the fields we want to force a recursive comparison on.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringOverriddenEqualsForTypes
public SELF ignoringOverriddenEqualsForTypes(Class<?>... types)
By default the recursive comparison uses overriddenequals
methods to compare fields, this method allows to force a recursive comparison for all fields of the given types (it adds them to the already registered ones).Since 3.17.0 all overridden
equals
so this method is only relevant if you have calledusingOverriddenEquals()
before.Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; // only compares number, ouch! @Override public boolean equals(final Object other) { if (!(other instanceof Address)) return false; Address castOther = (Address) other; return Objects.equals(number, castOther.number); } } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.80); sherlock2.home.address.street = "Butcher Street"; sherlock2.home.address.number = 221; // Assertion succeeds because: // - overridden equals are used // - Address has overridden equals and does not compare street fields. assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .isEqualTo(sherlock2); // ignoringOverriddenEqualsForTypes force a recursive comparison on the given types. // Assertion fails because: // - Address equals is not used. // - street fields are compared and differ. assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .ignoringOverriddenEqualsForTypes(Address.class) .isEqualTo(sherlock2);
- Parameters:
types
- the types we want to force a recursive comparison on.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringOverriddenEqualsForFieldsMatchingRegexes
public SELF ignoringOverriddenEqualsForFieldsMatchingRegexes(String... regexes)
In case you have instructed the recursive to use overriddenequals
withusingOverriddenEquals()
, this method allows to force a recursive comparison for the fields matching the given regexes (it adds them to the already registered ones).Since 3.17.0 all overridden
equals
so this method is only relevant if you have calledusingOverriddenEquals()
before.Nested fields can be specified by using dots like:
home\.address\.street
(\
is used to escape dots since they have a special meaning in regexes).Example:
public class Person { String name; double height; Home home = new Home(); } public class Home { Address address = new Address(); } public static class Address { int number; String street; // only compares number, ouch! @Override public boolean equals(final Object other) { if (!(other instanceof Address)) return false; Address castOther = (Address) other; return Objects.equals(number, castOther.number); } } Person sherlock = new Person("Sherlock", 1.80); sherlock.home.address.street = "Baker Street"; sherlock.home.address.number = 221; Person sherlock2 = new Person("Sherlock", 1.80); sherlock2.home.address.street = "Butcher Street"; sherlock2.home.address.number = 221; // assertion succeeds because overridden equals are used and thus street fields are mot compared assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .isEqualTo(sherlock2); // ignoringOverriddenEqualsForFields force a recursive comparison on the field matching the regex // now this assertion fails as we expect since the home.address.street fields differ assertThat(sherlock).usingRecursiveComparison() .usingOverriddenEquals() .ignoringOverriddenEqualsForFieldsMatchingRegexes("home.*") .isEqualTo(sherlock2);
- Parameters:
regexes
- regexes used to specify the fields we want to force a recursive comparison on.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringCollectionOrder
public SELF ignoringCollectionOrder()
Makes the recursive comparison to ignore collection order in all fields in the object under test.Example:
public class Person { String name; List<Person> friends = new ArrayList<>(); } Person sherlock1 = new Person("Sherlock Holmes"); sherlock1.friends.add(new Person("Dr. John Watson")); sherlock1.friends.add(new Person("Molly Hooper")); Person sherlock2 = new Person("Sherlock Holmes"); sherlock2.friends.add(new Person("Molly Hooper")); sherlock2.friends.add(new Person("Dr. John Watson")); // assertion succeeds as all fields collection order is ignored in the comparison assertThat(sherlock1).usingRecursiveComparison() .ignoringCollectionOrder() .isEqualTo(sherlock2); // assertion fails as fields collection order is not ignored in the comparison assertThat(sherlock1).usingRecursiveComparison() .isEqualTo(sherlock2);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringCollectionOrderInFields
public SELF ignoringCollectionOrderInFields(String... fieldsToIgnoreCollectionOrder)
Makes the recursive comparison to ignore collection order in the object under test specified fields. Nested fields can be specified like this:home.address.street
.Example:
public class Person { String name; List<Person> friends = new ArrayList<>(); List<Person> enemies = new ArrayList<>(); } Person sherlock1 = new Person("Sherlock Holmes"); sherlock1.friends.add(new Person("Dr. John Watson")); sherlock1.friends.add(new Person("Molly Hooper")); sherlock1.enemies.add(new Person("Jim Moriarty")); sherlock1.enemies.add(new Person("Irene Adler")); Person sherlock2 = new Person("Sherlock Holmes"); sherlock2.friends.add(new Person("Molly Hooper")); sherlock2.friends.add(new Person("Dr. John Watson")); sherlock2.enemies.add(new Person("Irene Adler")); sherlock2.enemies.add(new Person("Jim Moriarty")); // assertion succeeds as friends and enemies fields collection order is ignored in the comparison assertThat(sherlock1).usingRecursiveComparison() .ignoringCollectionOrderInFields("friends", "enemies") .isEqualTo(sherlock2); // assertion fails as enemies field collection order differ and it is not ignored assertThat(sherlock1).usingRecursiveComparison() .ignoringCollectionOrderInFields("friends") .isEqualTo(sherlock2);
- Parameters:
fieldsToIgnoreCollectionOrder
- the fields of the object under test to ignore collection order in the comparison.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
ignoringCollectionOrderInFieldsMatchingRegexes
public SELF ignoringCollectionOrderInFieldsMatchingRegexes(String... regexes)
Makes the recursive comparison to ignore collection order in the object under test fields matching the specified regexes.Nested fields can be specified by using dots like this:
home\.address\.street
(\
is used to escape dots since they have a special meaning in regexes).Example:
public class Person { String name; List<Person> friends = new ArrayList<>(); List<Person> enemies = new ArrayList<>(); } Person sherlock1 = new Person("Sherlock Holmes"); sherlock1.friends.add(new Person("Dr. John Watson")); sherlock1.friends.add(new Person("Molly Hooper")); sherlock1.enemies.add(new Person("Jim Moriarty")); sherlock1.enemies.add(new Person("Irene Adler")); Person sherlock2 = new Person("Sherlock Holmes"); sherlock2.friends.add(new Person("Molly Hooper")); sherlock2.friends.add(new Person("Dr. John Watson")); sherlock2.enemies.add(new Person("Irene Adler")); sherlock2.enemies.add(new Person("Jim Moriarty")); // assertion succeeds as friends and enemies fields collection order is ignored in the comparison assertThat(sherlock1).usingRecursiveComparison() .ignoringCollectionOrderInFieldsMatchingRegexes("friend.", "enemie.") .isEqualTo(sherlock2); // assertion fails as enemies field collection order differ and it is not ignored assertThat(sherlock1).usingRecursiveComparison() .ignoringCollectionOrderInFields("friend.") .isEqualTo(sherlock2);
- Parameters:
regexes
- regexes used to find the object under test fields to ignore collection order in the comparison.- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
withStrictTypeChecking
public SELF withStrictTypeChecking()
Makes the recursive comparison to check that actual's type is compatible with expected's type (and do the same for each field).
Compatible means that the expected's type is the same or a subclass of actual's type.Examples:
public class Person { String name; double height; Person bestFriend; } Person sherlock = new Person("Sherlock", 1.80); sherlock.bestFriend = new Person("Watson", 1.70); Person sherlockClone = new Person("Sherlock", 1.80); sherlockClone.bestFriend = new Person("Watson", 1.70); // assertion succeeds as sherlock and sherlockClone have the same data and types assertThat(sherlock).usingRecursiveComparison() .withStrictTypeChecking() .isEqualTo(sherlockClone); // Let's now define a data structure similar to Person public class PersonDTO { String name; double height; PersonDTO bestFriend; } PersonDTO sherlockDto = new PersonDTO("Sherlock", 1.80); sherlockDto.bestFriend = new PersonDTO("Watson", 1.70); // assertion fails as Person and PersonDTO are not compatible even though they have the same data assertThat(sherlock).usingRecursiveComparison() .withStrictTypeChecking() .isEqualTo(noName); // Let's define a subclass of Person public class Detective extends Person { boolean busy; } Detective detectiveSherlock = new Detective("Sherlock", 1.80); detectiveSherlock.bestFriend = new Person("Watson", 1.70); detectiveSherlock.busy = true; // assertion succeeds as Detective inherits from Person and // only Person's fields are included into the comparison. assertThat(sherlock).usingRecursiveComparison() .withStrictTypeChecking() .isEqualTo(detectiveSherlock);
- Returns:
- this
RecursiveComparisonAssert
to chain other methods.
-
withEqualsForFields
public SELF withEqualsForFields(BiPredicate<?,?> equals, String... fieldLocations)
Allows to register aBiPredicate
to compare fields with the given locations. A typical usage is for comparing double/float fields with a given precision.BiPredicates specified with this method have precedence over the ones registered with
withEqualsForType(BiPredicate, Class)
or the comparators registered withwithComparatorForType(Comparator, Class)
.Note that registering a
BiPredicate
for a given field will override the previously registered Comparator (if any).The field locations must be specified from the root object, for example if
Foo
has aBar
field which has anid
, one can register to a comparator for Bar'sid
by calling:withEqualsForFields(idBiPredicate, "foo.id", "foo.bar.id")
Complete example:
public class TolkienCharacter { String name; double height; } TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2); TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3); TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9); BiPredicate<Double, Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5; // assertion succeeds assertThat(frodo).usingRecursiveComparison() .withEqualsForFields(closeEnough, "height") .isEqualTo(tallerFrodo); // assertion fails assertThat(frodo).usingRecursiveComparison() .withEqualsForFields(closeEnough, "height") .isEqualTo(reallyTallFrodo);
- Parameters:
equals
- theBiPredicate
to use to compare the given fieldsfieldLocations
- the location from the root object of the fields the BiPredicate should be used for- Returns:
- this
RecursiveComparisonAssert
to chain other methods. - Throws:
NullPointerException
- if the given BiPredicate is null.
-
withComparatorForFields
public SELF withComparatorForFields(Comparator<?> comparator, String... fieldLocations)
Allows to register a comparator to compare fields with the given locations. A typical usage is for comparing double/float fields with a given precision.Comparators registered with this method have precedence over comparators registered with
withComparatorForType(Comparator, Class)
orBiPredicate
registered withwithEqualsForType(BiPredicate, Class)
.The field locations must be specified from the root object, for example if
Foo
has aBar
field which has anid
, one can register to a comparator for Bar'sid
by calling:withComparatorForFields(idComparator, "foo.id", "foo.bar.id")
Note that registering a
Comparator
for a given field will override the previously registered BiPredicate/Comparator (if any).Complete example:
public class TolkienCharacter { String name; double height; } TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2); TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3); TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9); Comparator<Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5 ? 0 : 1; // assertion succeeds assertThat(frodo).usingRecursiveComparison() .withComparatorForFields(closeEnough, "height") .isEqualTo(tallerFrodo); // assertion fails assertThat(frodo).usingRecursiveComparison() .withComparatorForFields(closeEnough, "height") .isEqualTo(reallyTallFrodo);
- Parameters:
comparator
- theComparator
to use to compare the given fieldsfieldLocations
- the location from the root object of the fields the comparator should be used for- Returns:
- this
RecursiveComparisonAssert
to chain other methods. - Throws:
NullPointerException
- if the given comparator is null.
-
withComparatorForType
public <T> SELF withComparatorForType(Comparator<? super T> comparator, Class<T> type)
Allows to register a comparator to compare the fields with the given type. A typical usage is for comparing double/float fields with a given precision.Comparators registered with this method have less precedence than comparators registered with
withComparatorForFields(Comparator, String...)
or BiPredicate registered withwithEqualsForFields(BiPredicate, String...)
.Note that registering a
Comparator
for a given type will override the previously registered BiPredicate/Comparator (if any).Example:
public class TolkienCharacter { String name; double height; } TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2); TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3); TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9); Comparator<Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5 ? 0 : 1; // assertion succeeds assertThat(frodo).usingRecursiveComparison() .withComparatorForType(closeEnough, Double.class) .isEqualTo(tallerFrodo); // assertion fails assertThat(frodo).usingRecursiveComparison() .withComparatorForType(closeEnough, Double.class) .isEqualTo(reallyTallFrodo);
- Type Parameters:
T
- the class type to register a comparator for- Parameters:
comparator
- theComparator
to use to compare the given fieldstype
- the type to be compared with the given comparator.- Returns:
- this
RecursiveComparisonAssert
to chain other methods. - Throws:
NullPointerException
- if the given comparator is null.
-
withEqualsForType
public <T> SELF withEqualsForType(BiPredicate<? super T,? super T> equals, Class<T> type)
Allows to register aBiPredicate
to compare the fields with the given type. A typical usage is for comparing double/float fields with a given precision.BiPredicates registered with this method have less precedence than the one registered with
withEqualsForFields(BiPredicate, String...)
or comparators registered withwithComparatorForFields(Comparator, String...)
.Note that registering a
BiPredicate
for a given type will override the previously registered BiPredicate/Comparator (if any).Example:
public class TolkienCharacter { String name; double height; } TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2); TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3); TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9); BiPredicate<Double, Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5; // assertion succeeds assertThat(frodo).usingRecursiveComparison() .withEqualsForType(closeEnough, Double.class) .isEqualTo(tallerFrodo); // assertion fails assertThat(frodo).usingRecursiveComparison() .withEqualsForType(closeEnough, Double.class) .isEqualTo(reallyTallFrodo);
- Type Parameters:
T
- the class type to register a BiPredicate for- Parameters:
equals
- theBiPredicate
to use to compare the given fieldstype
- the type to be compared with the given comparator.- Returns:
- this
RecursiveComparisonAssert
to chain other methods. - Throws:
NullPointerException
- if the given BiPredicate is null.
-
withTypeComparators
SELF withTypeComparators(TypeComparators typeComparators)
-
registerComparatorForType
private void registerComparatorForType(Map.Entry<Class<?>,Comparator<?>> entry)
-
getRecursiveComparisonConfiguration
public RecursiveComparisonConfiguration getRecursiveComparisonConfiguration()
Returns theRecursiveComparisonConfiguration
currently used.- Returns:
- the
RecursiveComparisonConfiguration
currently used
-
determineDifferencesWith
private List<ComparisonDifference> determineDifferencesWith(Object expected)
-
-