如何在开发周期中识别未添加断言的Assertj assertThat调用?
当然可以!这种只调用assertThat(object.getField())却不跟进具体断言的测试完全是无效的——它根本没验证任何逻辑,只是创建了一个Assertj断言对象就完事了,相当于白写。下面给你几种在开发周期里揪出这类问题的方案,包括你提到的自定义Sonar规则的具体实现思路:
方案一:IDE静态代码检查(实时反馈,开发阶段就堵漏洞)
很多主流IDE都能快速配置这类检查,让开发者写代码时立刻发现问题:
- 以IntelliJ IDEA为例,你可以创建结构化搜索检查:
- 打开
File > Settings > Editor > Inspections > General > Structural Search Inspection - 点击「Add」新建搜索模板,模板内容写:
assertThat($expression$); - 设置约束:确保这个语句是独立的
ExpressionStatement(也就是到assertThat()就结束,没有后续链式调用),$expression$可以匹配任意表达式 - 将这个检查的级别设为「Error」,这样IDE会实时标红这类无效代码
- 打开
- Eclipse也可以通过类似的自定义规则或者Assertj相关插件实现,核心思路都是识别孤立的
assertThat()语句
方案二:自定义SonarQube规则(团队级统一管控)
你提到的自定义Sonar规则完全可行,核心是识别那些调用完assertThat()后没有链式调用任何断言方法的孤立语句。具体实现步骤如下:
- 基于SonarJava API开发自定义规则:
- 先熟悉SonarJava的规则开发框架,创建一个Java项目作为Sonar插件
- 分析Assertj的方法特征:
assertThat()方法返回的是Assertion的子类(比如ObjectAssert、StringAssert)- 有效的断言方法(比如
isEqualTo()、isNull()、contains())要么返回void,要么返回当前断言对象用于链式调用 - 我们要找的是:
assertThat()调用直接作为一条语句结束,没有后续调用的情况
- 编写规则逻辑:
- 遍历AST(抽象语法树)中的所有方法调用节点,找到方法名为
assertThat的调用 - 检查该节点的父节点:如果父节点是
ExpressionStatement(说明这条语句到assertThat()就终止了),同时这个调用没有被赋值给变量(比如排除ObjectAssert<String> assert = assertThat(str);这种合法场景),就标记为违规
- 遍历AST(抽象语法树)中的所有方法调用节点,找到方法名为
- 打包规则成Sonar插件,部署到团队的Sonar服务器,配置为强制检查的规则,这样代码提交后就能自动扫描出问题
方案三:CI阶段的字节码/静态扫描
如果不想依赖Sonar,也可以在CI构建阶段做检查:
- 用ASM这类字节码工具扫描测试类的class文件,识别所有孤立的
assertThat()调用 - 或者写一个简单的JUnit扩展,在测试执行前后扫描测试类的字节码,一旦发现无效断言就抛出异常,阻断CI流程
- 这种方案适合小型团队,或者需要在构建阶段直接拦截无效测试的场景
额外提醒:规范团队的Assertj使用习惯
其实最根本的是统一团队的测试规范:
- 明确要求任何
assertThat()调用必须紧跟至少一个断言方法,比如assertThat(user.getAge()).isGreaterThan(18); - 如果只是想验证表达式不抛出异常,应该用
assertThatCode(() -> object.getField()).doesNotThrowAnyException();,而不是孤零零的assertThat(object.getField());
内容的提问来源于stack exchange,提问作者TomVW
相关产品推荐
相关产品推荐

