声纳分支覆盖类声明

时间:2013-06-07 15:44:29

标签: java code-coverage sonarqube

我在声纳有一节课:

public class Foo {
..... much code ....
}

Sonar正在报告public class Foo行覆盖的1/2分支。这是什么意思?你如何测试一个声明一个类的行?

编辑:如果重要,这是Sonar v3.5。

编辑2:显示我的意思的屏幕截图,请注意第9行“公共类”旁边的1/2。当悬停在此上方时,我得到一个工具提示,指出“测试覆盖了1个分支”

http://img829.imageshack.us/img829/2626/screenshot20130607at120.png

编辑#3:好的,经过一番调查,我把它缩小到我能找到的最小片段,触发了这个:

public class Foo {

    Foo(final String s) {
        assert (s != null);
    }
}

如果构造函数中不存在该断言,则在Sonar中不会生成“N / 2分支覆盖”标志。如果断言消失了,那么旗帜也会消失。所以我的 guess 是它基于构造函数中的分支? (此代码的断言行覆盖0/4分支,公共类行覆盖0/2)。

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 的回答所写,字节码在类声明的同一行具有隐式构造函数,不确定)

由于它是实用程序类,我们从未在测试中初始化该类的对象,因此未涵盖默认构造函数。所以我添加了私有构造函数并解决了问题。顺便说一句,声纳还标记了私有构造函数的代码异味。