AssertJ因toString循环引用报错,如何自定义错误报告不调用toString方法?
解决方案
完全可以实现,AssertJ提供了自定义对象字符串表示的能力,无需修改原有业务代码,以下是两种可行实现方式:
方案1:全局注册自定义表示器(推荐,一次配置全测试生效)
通过自定义Representation重写对象的序列化逻辑,全局生效后所有AssertJ断言都会优先使用你定义的规则生成错误信息:
- 自定义表示器实现
import org.assertj.core.presentation.StandardRepresentation; public class EntityIdRepresentation extends StandardRepresentation { @Override protected String toStringOf(Object object) { // 匹配你所有存在循环引用的实体类,也可判断是否实现了有getId()的通用接口 if (object instanceof YourEntity) { return String.format("YourEntity(id=%s)", ((YourEntity) object).getId()); } // 其他类型走默认逻辑 return super.toStringOf(object); } // 如果有多个实体类,可扩展通用判断逻辑,比如通过反射判断是否存在getId()方法: // private String tryGetId(Object obj) { // try { // Method getIdMethod = obj.getClass().getMethod("getId"); // return String.format("%s(id=%s)", obj.getClass().getSimpleName(), getIdMethod.invoke(obj)); // } catch (Exception e) { // return super.toStringOf(obj); // } // } }
- 全局注册配置
在测试类的静态初始化块或者@BeforeAll方法中注册即可:
import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeAll; public class YourTest { @BeforeAll static void configAssertJ() { Assertions.setGlobalRepresentation(new EntityIdRepresentation()); } // 你的测试方法,直接写原有断言即可 @Test void testList() { assertThat(list1).containsExactly(item1, item2); } }
方案2:针对单次断言单独指定
如果不需要全局生效,只想针对特定断言修改表示逻辑,可以用usingRepresentation方法:
// 直接在断言链上指定自定义表示器即可 assertThat(list1) .usingRepresentation(new EntityIdRepresentation()) .containsExactly(item1, item2);
注意事项
如果你的实体类被AOP、JPA等框架生成了代理子类,判断类型时建议通过父类/接口匹配,或者过滤代理类前缀(如$$EnhancerByCGLIB$$),避免匹配失败。
内容的提问来源于stack exchange,提问作者pirho
相关产品推荐
相关产品推荐

