Search code examples
kotlinassertj

AssertJ: `ignoringFields` is not ignoring all the provided fields?


I want to compare two objects using org.assertj.core.api.Assertions.assertThat from version 3.14.0:

assertThat(getActual())
        .usingRecursiveComparison()
        .ignoringFields("customer", "orders", "\$hashCode", "fragments.parentFields.__typename", "fragments.parentFields.image")
        .isEqualTo(orderForm)

When I do so I get the following error:

when recursively comparing field by field, but found the following difference:

field/property 'fragments' differ:
- actual value   : Fragments{parentFields=Optional[ParentFields{__typename=OrderForm, id=1, image=Image{__typename=Image, id=71, accuracy=100.0, type=ORDER_FORM, state=AUTOMATIC, value=order form, base64=}}]}
- expected value : Fragments{parentFields=Optional[ParentFields{__typename=ParentFields, id=1, image=Image{__typename=Image, id=123, accuracy=99.99, type=NONE, state=NONE, value=value, base64=base64}}]}

The recursive comparison was performed with this configuration:
- the following fields were ignored in the comparison: customer, orders, $hashCode, fragments.parentFields.__typename, fragments.parentFields.image
- overridden equals methods were used in the comparison
- these types were compared with the following comparators:
  - java.lang.Double -> DoubleComparator[precision=1.0E-15]
  - java.lang.Float -> FloatComparator[precision=1.0E-6]
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).

From my understanding, ignoring all the fileds I added to the ignoreingFields function the comparison should be:

- actual value   : Fragments{parentFields=Optional[ParentFields{id=1}]}
- expected value : Fragments{parentFields=Optional[ParentFields{id=1}]} 

And thus it should not fail, it should succeed.

The other ignored fileds (customer, orders, \$hashCode) are getting ignored correctly. So I wonder if there is something wrong with fields of nested objects. But in the javadoc I found:

* // assertion succeeds as name and home.address.street fields are ignored in the comparison
* assertThat(sherlock).usingRecursiveComparison()
*                     .ignoringFields("name", "home.address.street")
*                     .isEqualTo(noName);

So I think im using it as intended by the API.

Ofcourse I could get around all this by simply doing:

assertThat(actual
        ?.fragments()
        ?.parentFields()
        ?.get()
        ?.id()
).isEqualTo(orderForm
        .fragments()
        .parentFields()
        .get()
        .id())

But I have many objects which I have to compare like that and which do not have the same super class. So im going to create something like:

fun assertCommons(actual: Any, expected: Any) {
    assertThat(actual)
        .usingRecursiveComparison()
        ....
}

So back to the question: What goes wrong with ignoring these fields?

EDIT

Since parentFields is an optional:

...
.ignoringFields("customer", "orders", "\$hashCode", "fragments.parentFields.get().__typename", "fragments.parentFields.get().image")
...
field/property 'fragments' differ:
- actual value   : Fragments{parentFields=Optional[ParentFields{__typename=OrderForm, id=1, image=Image{__typename=Image, id=71, accuracy=100.0, type=ORDER_FORM, state=AUTOMATIC, value=order form, base64=}}]}
- expected value : Fragments{parentFields=Optional[ParentFields{__typename=ParentFields, id=1, image=Image{__typename=Image, id=123, accuracy=99.99, type=NONE, state=NONE, value=value, base64=base64}}]}

The recursive comparison was performed with this configuration:
 - the following fields were ignored in the comparison: customer, orders, $hashCode, fragments.parentFields.get().__typename, fragments.parentFields.get().image
 - overridden equals methods were used in the comparison
 - these types were compared with the following comparators:
 - java.lang.Double -> DoubleComparator[precision=1.0E-15]
 - java.lang.Float -> FloatComparator[precision=1.0E-6]
 - actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).

With value instead of get()

...
.ignoringFields("customer", "orders", "\$hashCode", "fragments.parentFields.value.__typename", "fragments.parentFields.value.image")
...
when recursively comparing field by field, but found the following difference:

field/property 'fragments' differ:
- actual value   : Fragments{parentFields=Optional[ParentFields{__typename=OrderForm, id=1, image=Image{__typename=Image, id=71, accuracy=100.0, type=ORDER_FORM, state=AUTOMATIC, value=order form, base64=Optional[]}}]}
- expected value : Fragments{parentFields=Optional[ParentFields{__typename=ParentFields, id=1, image=Image{__typename=Image, id=123, accuracy=99.99, type=NONE, state=NONE, value=value, base64=Optional[base64]}}]}

The recursive comparison was performed with this configuration:
- the following fields were ignored in the comparison: customer, orders, $hashCode, fragments.parentFields.value
- overridden equals methods were used in the comparison
- these types were compared with the following comparators:
  - java.lang.Double -> DoubleComparator[precision=1.0E-15]
  - java.lang.Float -> FloatComparator[precision=1.0E-6]
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).

Solution

  • "fragments.parentFields.get().__typename" is not a valid declaration for what you intend to do. when specifying "a.b.c" what AssertJ it going to do is try finding getA().getB().getC() or a.b.c or nay combination of field/getter (like getA().b.getC().

    Specifying fragments.parentFields.get() is not going to work as there is no field named get(). Try using value instead as this is the field returned by get() (AssertJ can read private fields).