assertj 中的 usingComparatorForType 似乎不适用于属于对象属性的对象属性

usingComparatorForType in assertj does not seem to apply to properties of objects that are properties of the object

我想测试两个对象的相等性,但对它们的某些嵌套属性中存在的 double 值的精度有一定的判断力。 usingComparatorForType seems to be an appropriate solution but it doesn't appear to work if my Foo object has a propery of type Bar where Bar.baz is a double which I want this precision discretion to apply to. The example for isEqualToComparingFieldByFieldRecursively 没有完全解决我要测试的情况。

一些示例代码

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

import java.util.Comparator;
import java.util.Objects;

import org.junit.Test;

public class ComparatorForTypeTest {

  private static final Comparator<Double> DOUBLE_COMPARATOR = new Comparator<Double>() {
    @Override
    public int compare(Double d1, Double d2) {
      return Math.abs(d1 - d2) <= 0.1 ? 0 : 1;
    }
  };

  class Foo {
    private int id;
    private double baz;
    private Bar bar;

    public Foo(int id, double baz, Bar bar) {
      this.id = id;
      this.baz = baz;
      this.bar = bar;
    }

    public Foo withBar(Bar bar) {
      Foo that = this;
      that.bar = bar;
      return that;
    }

    @Override
    public int hashCode() {
      return Objects.hash(id, baz, bar);
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      } else if (obj == null || obj.getClass() != Foo.class) {
        return false;
      }

      Foo that = (Foo) obj;
      return Objects.equals(this.id, that.id)
          && Objects.equals(this.baz, that.baz)
          && Objects.equals(this.bar, that.bar);
    }

    @Override
    public String toString() {
      return String.format("Foo[id=%d, score=%f, bar=%s]", id, baz, bar == null ? null : bar.toString());
    }
  }

  class Bar {
    private int id;
    private double baz;

    public Bar(int id, double baz) {
      this.id = id;
      this.baz = baz;
    }

    @Override
    public int hashCode() {
      return Objects.hash(id, baz);
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      } else if (obj == null || obj.getClass() != Bar.class) {
        return false;
      }

      Bar that = (Bar) obj;
      return Objects.equals(this.id, that.id)
          && Objects.equals(this.baz, that.baz);
    }

    @Override
    public String toString() {
      return String.format("Bar[id=%d, score=%f]", id, baz);
    }
  }

  @Test
  public void itComparesBars() {
    Bar a = new Bar(1, 1.4);
    Bar b = new Bar(1, 1.45);
    Bar c = new Bar(2, 1.4);

    assertThat(a).isNotEqualTo(b);
    assertThat(b).isNotEqualTo(c);
    assertThat(a).isNotEqualTo(c);

    assertThat(a).usingComparatorForType(DOUBLE_COMPARATOR, Double.class).isEqualToComparingFieldByField(b);
  }

  @Test
  public void itComparesFoos() {
    Foo a = new Foo(1, 1.4, null);
    Foo b = new Foo(1, 1.45, null);
    Foo c = new Foo(2, 1.4, null);

    assertThat(a).isNotEqualTo(b);
    assertThat(b).isNotEqualTo(c);
    assertThat(a).isNotEqualTo(c);

    assertThat(a).usingComparatorForType(DOUBLE_COMPARATOR, Double.class).isEqualToComparingFieldByField(b);

    Bar barA = new Bar(1, 1.4);
    Bar barB = new Bar(1, 1.45);

    assertThat(a.withBar(barA)).usingComparatorForType(DOUBLE_COMPARATOR, Double.class).isEqualToComparingFieldByFieldRecursively(b.withBar(barA));
    assertThat(a.withBar(barA)).usingComparatorForType(DOUBLE_COMPARATOR, Double.class).isEqualToComparingFieldByFieldRecursively(b.withBar(barB));
  }
}

在这种情况下,itComparesFoos 是我希望应用关于双精度的自由裁量权的地方。

这里的问题是 Bar 有一个覆盖的 equals 方法,它用于比较 Bar 个实例,这在 javadoc 中提到(但我知道 javadoc 并不总是发现 API):

的最佳方式

The recursive property/field comparison is not applied on fields having a custom equals implementation, i.e. the overridden equals method will be used instead of a field by field comparison.

https://github.com/joel-costigliola/assertj-core/issues/1002 is a ticket to revamp the recursive comparison api which has gone wild, it will provide an option to force recursive comparison even if equals was overridden (likely forcingRecursiveComparisonForAll).