市场上有很多 Java 代码分析工具,其中一些甚至被用作事实上的标准,例如 Checkstyle、PMD 和 SpotBugs,它们对于防止开发人员犯许多常见错误和编码错误,从而加快速度具有巨大的价值。加快开发流程、减少错误修复工作等等。

背景和动机 几年前,我参与了一个巨大的项目,当然,该项目使用这些库来提高软件质量并帮助开发人员生活。

我所在的一个小团队正在开发一个供内部使用的基于 Java 的测试自动化框架,但它在我们的团队中得到了广泛的使用——不仅是测试自动化工程师,还包括后端和前端开发人员,因此,我们不可避免地会遇到一些常见的错误和误用。

有一段时间,它工作得很好,我们在代码审查过程中识别了它们,但一段时间后,我想确保这些编码错误甚至不会达到拉取请求,从而降低代码审查工作量,甚至会被在 IDE 中编码过程中显示。

然后,我就碰到了IntelliJ的检查。

很明显,IntelliJ 具有内置检查(甚至针对特定的 Java 库和框架),但您也可以通过其名为“结构搜索和替换模板”的工具进行自定义检查。这是一个派上用场的功能,因为我能够专门为我们的框架创建自定义代码检查。现在,我可以使用 PMD 来创建它们,但我不确定是否需要重新实现此类检查才能与 IntelliJ 检查插件一起使用(但它们肯定需要一个插件作为 PMD 和 IntelliJ 之间的适配器) ),并且由于这个结构搜索和替换工具不是一个有详细记录的功能,所以我感受到了挑战,并且我有一个电话来尝试它。

该工具有一个基于 GUI 的编辑器,可以生成 XML 配置。这就是我将在本文中详细介绍的内容。

让我们使用 Mockito 库中的一个示例。

Mockito 示例 在 Mockito 的某个版本之前,不可能模拟/监视最终类,即使在该版本之后,内联模拟功能现在默认也是禁用的。因此,我想仍然有许多项目使用 Mockito 版本或使用 Mockito 的方式无法模拟最终类。

现在,当我编写单元测试时,有时我会编写整个单元测试,比如说需要 10-15 分钟才能弄清楚如何模拟被测类的依赖关系。然后,当我运行测试时,结果发现其中一个类无法被模拟,因为它是最终的,甚至可能是最终的,所以我的测试基本上基于一个错误的假设。

对此进行检查,甚至在运行测试之前突出显示有问题的代码片段,并向我显示一条消息,上面写着“最终类不能被模拟,你这个白痴!”会非常有用,而且我本可以节省时间并将其花在其他任务上。将浪费的时间乘以犯此错误或类似错误的次数,您就可以计算出通过这样的简单检查可以节省多少时间。

我做了一些调查,发现有许多库没有自己的 XML 形式的检查,尤其是IntelliJ 插件的形式。

一个很大的例外是 Lombok 的 IntelliJ 插件(如果我们只讨论特定的库),但我也可以提到一些 Checkstyle 和 PMD 插件。但我找不到 Mockito 的。

组装定制检查 如果字段类型(而不是字段本身)是最终的,让我们创建一个检查@Mock和带注释的字段,将它们标记为有问题。@Spy

您可以在Settings > Editor > Inspections > General > Structural Search Inspection下找到自定义检查。首先,您需要启用它;之后,在右侧,您可以添加搜索模板或替换模板。它们之间的区别在于,前者仅突出显示代码片段;后者仅突出显示代码片段。后一个还为该特定代码部分提供了快速修复。

图片标题

我不会提供组装模板的分步教程,但我将对其工作原理进行简要说明。

以下是整个检查的模板文本(带有字符括起来的可自定义模板变量$):

1 类 $类$ { 2 @$MockAnnotation$ ( ) 3 @Modifier ( "实例" ) $FieldType$  $Field$  =  $Init$ ; 4 } 图片标题

我认为它很容易理解,并且对这里发生的事情有一个很好的视觉表示,至少部分地:检查应该搜索至少注释为 的类的实例字段@Mock。唯一缺少的部分是字段类型应该是最终的。

我们来看看模板变量的配置。

人们可以在它们上定义不同的过滤器,通过这些过滤器可以将搜索限制为某些值和数据,或者通过自定义验证逻辑来​​丰富搜索。

该$MockAnnotation$变量定义了一个文本过滤器,其中注释被引用为正则表达式:org\.mockito\.(Mock|Spy)以搜索这两个注释。

该$Field$变量有两个过滤器:

计数过滤器定义为 [1,Infinite] 范围,告诉工具可能至少有一个或无数次出现此类字段,以便您确保找到并突出显示所有字段。 脚本过滤器,您可以在其中编写所需的任何类型的 Groovy 脚本,能够编写任何自定义验证逻辑,并具有访问 IntelliJ 内部 API 的额外能力: 1 场地。getType (). 解决()。hasModifierProperty(“最终”)

在脚本过滤器中,您可以引用模板变量(在本例中为 Field),该变量被作为 AST 节点处理(实际上是 IntelliJ 自己的 AST 实现);字段的类型转换为类 AST 节点类型,可以在该类型上查询修饰符。脚本过滤器的返回值应该是布尔值;在这种情况下,字段类型是否是最终的。

该$Init$变量具有定义为 [0,1] 范围的计数过滤器,使得初始化部分在搜索中可选。

在这里,您可以看到正在进行的检查:

图片标题

优点和缺点 当然,这个工具和解决方案也有其自身的局限性和优缺点,所以我想从两方面来说一下其中的一些。

优点 无论是这种形式还是作为 IntelliJ 插件、特定于库的检查、发出误用或不良结构的信号,甚至为它们提供替换/快速修复,此工具:

甚至可以在构建甚至启动测试或应用程序之前帮助发现编码问题, 有助于减少开发和代码审查工作 这使得整个开发过程和代码质量更快更好。

缺点 虽然我发现这些检查通常很有用,但以这种形式,它们可能不是最适合开发和维护大量应用程序的项目,因为这些检查的维护可能会随之显着增加。IntelliJ 插件会更合适;该项目只需要确保每个人都安装并使用它。

推荐阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: