Search code examples
assertj

Comparing two objects with "special" assertions for certain fields with AssertJ


Given the following class...

public class UserAccount {
  private Long id;
  private String email;
  private String activationCode;
  private Date createDate;
}

... I need to compare the actual object with an expected object using AssertJ. However the fields id, activationCode and createDate have dynamic value which I can't hard-code into the assertion.

So the following assertion would fail:
assertThat(actualUserAccount).isEqualTo(expectedUserAccount);

Then I found the following which would ignore certain fields:

assertThat(actualUserAccount)
        .usingRecursiveComparison()
        .ignoringFields("id", "activationCode", "createDate")
        .isEqualTo(expectedUserAccount);

But what I'm actually looking for is to assert for the objects being equal with the following special checks on certain fields:

  • Is there an id with any Long value?
  • Is there an activationCode with any String value?
  • Is there an createDate with any Date value?

Or is there no other way than to write one assertion for each field?


Solution

  • You can specify how to compare certain fields with withEqualsForFields so you could write something like:

    assertThat(actualUserAccount)
            .usingRecursiveComparison()
            .withEqualsForFields((id1, id2) -> id1 instanceof Long && id2 instanceof Long, "id")
            .isEqualTo(expectedUserAccount);
    

    I'm checking both ids fields since there is no garantee that id1 is the actual id and id2 the expected id.

    You could also write a generic method like BiPredicate<A, B> isType(T type) that returns a bipredicate checking both parameters are of the type T (my suggested signature might not work but you get the idea), that would let you write:

    assertThat(actualUserAccount)
            .usingRecursiveComparison()
            .withEqualsForFields(isType(Long.class), "id")
            .withEqualsForFields(isType(String.class), "activationCode")
            .withEqualsForFields(isType(Date.class), "createDate")
            .isEqualTo(expectedUserAccount);
    

    Here's what isType looks like (I haven't tested it though):

    <A, B, T extends Class<?>> BiPredicate<A, B> isType(T type) {
        return (a, b) -> type.isInstance(a) && type.isInstance(b);
    }
    

    Having said that, I would probably not go that way and write additional assertions.

    For reference: https://assertj.github.io/doc/#assertj-core-recursive-comparison-comparators