【问题标题】:Comparing two objects with "special" assertions for certain fields with AssertJ使用 AssertJ 将两个对象与某些字段的“特殊”断言进行比较
【发布时间】:2021-06-05 21:35:59
【问题描述】:

鉴于以下课程...

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

... 我需要使用 AssertJ 将实际对象与预期对象进行比较。但是,id、activationCode 和 createDate 字段具有动态值,我无法将其硬编码到断言中。

所以下面的断言会失败:
assertThat(actualUserAccount).isEqualTo(expectedUserAccount);

然后我发现以下内容会忽略某些字段:

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

但我真正要寻找的是通过对某些字段进行以下特殊检查来断言对象是否相等:

  • 是否存在带有任何 Long 值的 id?
  • 是否存在带有任何 String 值的 activationCode?
  • 是否存在带有任何 Date 值的 createDate?

或者除了为每个字段编写一个断言之外别无他法?

【问题讨论】:

    标签: assertj


    【解决方案1】:

    如果你想验证所有字段都有一个值,你可以使用hasNoNullFieldsOrProperties,而returns可以用来细化email的验证(假设getter暴露):

    assertThat(actualUserAccount)
      .hasNoNullFieldsOrProperties()
      .returns(expectedUserAccount.getEmail(), from(UserAccount::getEmail));
    

    如果你必须强制字段的类型,你可以链接:

      .extracting(UserAccount::getId, UserAccount::getEmail, UserAccount::getActivationCode, UserAccount::getCreateDate)
      .hasExactlyElementsOfTypes(Long.class, String.class, String.class, Date.class);
    

    如果 getter 不可用,您的原始示例可能是验证 email 值的唯一选择:

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

    但您仍然可以使用extracting(String...) 而不是extracting(Function...) 来强制字段的类型:

    assertThat(actualUserAccount)
      .extracting("id", "email", "activationCode", "createDate")
      .hasExactlyElementsOfTypes(Long.class, String.class, String.class, Date.class);
    

    但是,这些选项对重构并不友好。

    【讨论】:

      【解决方案2】:

      您可以指定如何将某些字段与withEqualsForFields 进行比较,这样您就可以编写如下内容:

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

      我正在检查两个 ids 字段,因为没有保证 id1 是实际 id 而 id2 是预期 id。

      你也可以写一个像BiPredicate<A, B> isType(T type)这样的通用方法,它返回一个双谓词,检查两个参数都是T类型(我建议的签名可能不起作用,但你明白了),这会让你写:

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

      这是isType 的样子(虽然我还没有测试过):

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

      话虽如此,我可能不会那样写额外的断言。

      供参考:https://assertj.github.io/doc/#assertj-core-recursive-comparison-comparators

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-02-11
        • 1970-01-01
        • 2019-05-11
        • 2011-08-18
        • 2011-03-15
        • 1970-01-01
        • 2014-02-13
        相关资源
        最近更新 更多