assertThat(actual).usingRecursiveComparison().ignoringAllOverriddenEquals().isEqualTo(expected) 的奇怪行为

Strange behavior of assertThat(actual).usingRecursiveComparison().ignoringAllOverriddenEquals().isEqualTo(expected)

我在 assertj 库中发现了一个有趣的递归比较行为。如果您比较 类 的对象是子 类,那么在比较过程中似乎会跳过 super 类 的字段。这是一个已知问题吗?还是我做错了什么?这是一个简短的例子:

import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class ExampleTest {

  @Test
  public void test() {
    MyException expected =
            new MyException("Expected text message");
    MyException actual = new MyException("Actual text message"); //values for the field Throwable.detailMessage are different
    assertThat(actual).usingRecursiveComparison().ignoringAllOverriddenEquals().isEqualTo(expected);
  }
}

class MyException extends RuntimeException {

  MyException(String message) {
    super(message);
  }
}

这个测试会在实际上不应该通过的时候通过,因为 actual.getMessage()expected.getMessage() 会显示不同的值。

显然,该库跳过了从驻留在 java.lang 中的超类继承的字段的比较。由于 MyException 正在使用从 java.lang.Throwable 继承的 detailMessage 字段,因此将被跳过。 这是来自 org.assertj.core.internal.Objects 的代码,似乎是造成这种行为的原因:

/**
   * Returns the declared fields of given class and its superclasses stopping at superclass in <code>java.lang</code>
   * package whose fields are not included.
   *
   * @param clazz the class we want the declared fields.
   * @return the declared fields of given class and its superclasses.
   */
  public static Set<Field> getDeclaredFieldsIncludingInherited(Class<?> clazz) {
    checkNotNull(clazz, "expecting Class parameter not to be null");
    Set<Field> declaredFields = getDeclaredFieldsIgnoringSyntheticAndStatic(clazz);
    // get fields declared in superclass
    Class<?> superclazz = clazz.getSuperclass();
    while (superclazz != null && !superclazz.getName().startsWith("java.lang")) {
      declaredFields.addAll(getDeclaredFieldsIgnoringSyntheticAndStatic(superclazz));
      superclazz = superclazz.getSuperclass();
    }
    return declaredFields;
  }