这个声纳页面基本上列出了不同代码覆盖分析工具采用的各种方法: 源代码插装(由Clover使用) 离线字节码插装(由Cobertura使用) 即时字节码插装(由Jacoco使用) 这三种方法是什么,哪一种最有效,为什么?如果效率问题的答案是“取决于”,那么请解释一下为什么?
源代码仪器化是在编译之前向源代码添加指令。这些指令用于跟踪哪些代码部分已被执行。离线字节码仪器化是在编译后直接将相同的指令添加到字节码中。在线字节码仪器化是在运行时,当JVM加载字节码时,动态地向字节码中添加相同的指令。 此页面对这些方法进行了比较。它可能存在偏见,因为它是Clover文档的一部分。根据您对“高效”的定义,选择您最喜欢的方法。我认为你不会得到很大的差异。它们都能完成工作,无论使用哪种方法,大局将是相同的。
一般而言,覆盖率的影响是相同的。源代码插装可以提供更高级的报告结果,因为字节码插装无法区分源行内的任何结构,因为代码块粒度仅以源行记录。想象一下我有两个嵌套的if语句(或者等效地,在单个行中使用 if(a && b) ... *)。源代码插装程序可以看到这些内容,并为if内的多个分支提供与源行相关的覆盖信息;它可以基于行和列报告块。但是字节码插装器只看到一个包围条件的行。如果条件a执行但为false,它是否将该行报告为“已覆盖”?您可能会认为这是一个罕见的情况(实际上可能是这样),因此没有太大用处。但是当您在其后遇到错误覆盖并出现场错误时,您可能会改变对其效用的看法。 这里有一个很好的例子和解释,说明了字节码覆盖率如何正确地获得switch语句的覆盖率,这是极其困难的。源代码插装程序还可以实现更快的测试执行,因为它具有编译器帮助优化插装代码的优势。特别是,二进制插装器在循环内插入探针可能会被JIT编译器编译到循环内部。一个好的Java编译器将看到插装程序产生了一个循环不变结果,并将插装程序提出循环(JIT编译器理论上也可以这样做;问题在于它们是否真的这样做)。