AssertJ中usingComparatorForType无法作用于嵌套对象的double属性问题
解决AssertJ嵌套对象中Double精度自定义比较的问题
嘿,我明白你遇到的问题了——想用AssertJ的usingComparatorForType来控制嵌套对象里Double字段的比较精度,但发现嵌套在Foo里的Bar对象的baz字段没生效。这其实是因为你用的isEqualToComparingFieldByFieldRecursively方法有个小坑:它在递归比较时会默认调用对象自身重写的equals方法,而不是你设置的自定义比较器。
要解决这个问题,你需要切换到AssertJ的递归比较API——usingRecursiveComparison(),它专门为这种嵌套字段比较设计,能正确把自定义比较器应用到所有层级的指定类型字段上。
修改后的测试代码
下面是调整后的itComparesFoos测试方法,直接看修改后的写法:
@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); // 直接比较Foo的Double字段,原来的写法没问题 assertThat(a) .usingComparatorForType(DOUBLE_COMPARATOR, Double.class) .isEqualToComparingFieldByField(b); Bar barA = new Bar(1, 1.4); Bar barB = new Bar(1, 1.45); // 情况1:Foo的其他字段一致,Bar对象完全相同,应该通过 assertThat(a.withBar(barA)) .usingRecursiveComparison() .isEqualTo(b.withBar(barA)); // 情况2:Foo的其他字段一致,Bar的baz在精度范围内,用自定义比较器让它通过 assertThat(a.withBar(barA)) .usingRecursiveComparison() .withComparatorForType(DOUBLE_COMPARATOR, Double.class) .isEqualTo(b.withBar(barB)); }
关键细节解释
- 为什么原来的写法失效?:
isEqualToComparingFieldByFieldRecursively在比较Bar对象时,会调用你重写的Bar.equals方法,而这个方法里是用Objects.equals(this.baz, that.baz)直接比较Double值,完全没用到你设置的自定义比较器,所以精度控制自然不生效。 usingRecursiveComparison()的优势:它会跳过对象自身的equals实现,直接遍历所有嵌套字段进行比较,并且会把你设置的withComparatorForType应用到所有层级的Double类型字段——不管是Foo自己的baz,还是嵌套Bar里的baz,都会用你的自定义规则比较。- 简化写法:如果你的精度需求是“允许一定误差范围”,其实不用自己写Comparator,AssertJ自带了
withPrecision方法,更简洁:
这个方法专门针对浮点类型,用法更直观。assertThat(a.withBar(barA)) .usingRecursiveComparison() .withPrecision(0.1) .isEqualTo(b.withBar(barB));
另外,你的自定义Double比较器也可以用Lambda简化一下:
private static final Comparator<Double> DOUBLE_COMPARATOR = (d1, d2) -> Math.abs(d1 - d2) <= 0.1 ? 0 : 1;
这样调整后,嵌套对象里的Double字段就能正确应用你的精度控制了~
内容的提问来源于stack exchange,提问作者Lorcan O'Neill
相关产品推荐
相关产品推荐

