如何用AssertJ递归比较字段名不同但值相同的两个对象
错误原因说明
你之前使用的withEqualsForFields仅适用于同名字段的自定义相等判断,无法解决字段名不匹配的问题。AssertJ在执行递归比较前会先校验目标对象是否包含源对象的所有字段,由于Entity不存在dtoFieldA、dtoFieldB、dtoFieldC三个字段,会直接抛出你遇到的错误,不会执行自定义的BiPredicate逻辑。
正确方案(要求AssertJ版本 >= 3.18.0)
AssertJ从3.18.0版本开始提供withFieldMappingAPI,专门用于处理字段名不匹配的映射场景,配置示例如下:
import static org.assertj.core.api.Assertions.assertThat; // 测试代码 assertThat(dto) .usingRecursiveComparison() // 按 源字段(DTO字段名) -> 目标字段(Entity字段名) 规则配置映射 .withFieldMapping("dtoFieldA", "entityFieldA") .withFieldMapping("dtoFieldB", "entityFieldB") .withFieldMapping("dtoFieldC", "entityFieldC") .isEqualTo(entity);
以上配置会自动完成:
- sameNameField1、sameNameField2两个同名字段的自动值比较
- 三个不同名字段按照映射关系匹配后比较值
- 不需要额外自定义BiPredicate即可完成普通值相等判断
如果有特殊比较逻辑(比如忽略大小写、空值特殊处理等),可以在配置映射后叠加自定义比较规则:
// 示例:dtoFieldA和entityFieldA比较时忽略大小写 BiPredicate<String, String> fieldAComparator = (dtoVal, entityVal) -> dtoVal.equalsIgnoreCase(entityVal); assertThat(dto) .usingRecursiveComparison() .withFieldMapping("dtoFieldA", "entityFieldA") .withFieldMapping("dtoFieldB", "entityFieldB") .withFieldMapping("dtoFieldC", "entityFieldC") .withEqualsForFields(fieldAComparator, "dtoFieldA") .isEqualTo(entity);
低版本兼容方案(AssertJ < 3.18.0)
如果使用的AssertJ版本不支持字段映射功能,可以先忽略不匹配的字段,再单独校验这几个字段:
// 先递归比较所有同名字段,忽略三个不匹配的DTO字段 assertThat(dto) .usingRecursiveComparison() .ignoringFields("dtoFieldA", "dtoFieldB", "dtoFieldC") .isEqualTo(entity); // 单独校验三个不同名字段的值 assertThat(dto.getDtoFieldA()).isEqualTo(entity.getEntityFieldA()); assertThat(dto.getDtoFieldB()).isEqualTo(entity.getEntityFieldB()); assertThat(dto.getDtoFieldC()).isEqualTo(entity.getEntityFieldC());
内容的提问来源于stack exchange,提问作者Bartłomiej Adamczyk
相关产品推荐
相关产品推荐

