我在声纳有一节课:
public class Foo {
..... much code ....
}
Sonar正在报告public class Foo
行覆盖的1/2分支。这是什么意思?你如何测试一个声明一个类的行?
编辑:如果重要,这是Sonar v3.5。
编辑2:显示我的意思的屏幕截图,请注意第9行“公共类”旁边的1/2。当悬停在此上方时,我得到一个工具提示,指出“测试覆盖了1个分支”
编辑#3:好的,经过一番调查,我把它缩小到我能找到的最小片段,触发了这个:
public class Foo {
Foo(final String s) {
assert (s != null);
}
}
如果构造函数中不存在该断言,则在Sonar中不会生成“N / 2分支覆盖”标志。如果断言消失了,那么旗帜也会消失。所以我的 guess 是它基于构造函数中的分支? (此代码的断言行覆盖0/4分支,公共类行覆盖0/2)。
答案 0 :(得分:7)
看起来这是与Sonar的JaCoCo代码覆盖组件相关的问题。 JaCoCo使用编译的字节码而不是Java源代码,Java编译器可以生成与底层源没有直接关系的代码。
查看JaCoCo的the docs,其中有一节(增加了重点):
在某些情况下,不明显的是,为什么特定的线条会突出显示或具有特定的颜色。原因是底层代码覆盖库JaCoCo仅适用于Java类文件。 在某些情况下,Java编译器会为特定的源代码行创建额外的字节代码。这种情况可能会被未来版本的JaCoCo / EclEmma过滤掉。
根据该段落中的链接将您带到Jacoco GH网站上的FilteringOptions页面,它提到了JDK可能产生代码的多种方式,这些方法将触发这些“虚假”代码覆盖警告。
然而,这不是在这里发挥作用(或不完全正确)。
如上所述,JaCoCo使用Java字节码,因此编译器生成的任何代码都不会直接归属于源代码。
在我的具体情况中,我有一个assert
,它在源代码中代表断言发生点的分支,但也代表“全局”级别。如果您查看上面定义的Foo
类的字节码(执行javap -c Foo
),您会看到:
Compiled from "Foo.java"
public class Foo extends java.lang.Object{
static final boolean $assertionsDisabled;
Foo(java.lang.String);
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: getstatic #2; //Field $assertionsDisabled:Z
7: ifne 22
10: aload_1
11: ifnonnull 22
14: new #3; //class java/lang/AssertionError
17: dup
18: invokespecial #4; //Method java/lang/AssertionError."<init>":()V
21: athrow
22: return
static {};
Code:
0: ldc_w #5; //class Foo
3: invokevirtual #6; //Method java/lang/Class.desiredAssertionStatus:()Z
6: ifne 13
9: iconst_1
10: goto 14
13: iconst_0
14: putstatic #2; //Field $assertionsDisabled:Z
17: return
注意第7行,它是一个条件分支,取决于是否启用了断言。因此,如果你有一个普通Java assert
的类,你将在字节码中的某个地方有这个分支,这就是在类声明中产生“N / 2个分支执行”覆盖警告的地方,其中N是0或1,取决于该类是否曾经通过测试(1)或不是(0)。
修改:请注意https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions中也提到了这一点:
抛出AssertionErrors的块 - 如果条件(如果!断言抛出新的AssertionError),则应忽略整个块
答案 1 :(得分:0)
我也遇到了同样的问题,其中一个实用程序类将类声明显示为未涵盖。 (实用程序类 - 具有所有静态实用程序方法的类)。最终发现声纳意味着抱怨默认构造函数是隐式的,没有被覆盖。由于它不是用代码编写的自定义构造函数,因此声纳在类声明中显示了问题。 (可能如@Adam Parkin 的回答所写,字节码在类声明的同一行具有隐式构造函数,不确定)
由于它是实用程序类,我们从未在测试中初始化该类的对象,因此未涵盖默认构造函数。所以我添加了私有构造函数并解决了问题。顺便说一句,声纳还标记了私有构造函数的代码异味。