6

我在声纳有一堂课:

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 个分支覆盖”标志。如果断言消失了,那么标志也会消失。所以我的猜测是它基于构造函数中的分支?(此代码包含 0/4 个分支用于断言行,0/2 用于公共类行)。

4

2 回答 2

7

看起来这是与 Sonar 的 JaCoCo 代码覆盖率组件相关的问题。JaCoCo 处理编译后的字节码而不是 Java 源代码,Java 编译器可以生成与底层源代码不直接相关的代码。

查看JaCoCo的文档,有一段内容如下(强调添加):

在某些情况下,为什么特定线条具有突出显示或具有特定颜色并不明显。原因是底层代码覆盖库 JaCoCo 仅适用于 Java 类文件。在某些情况下,Java 编译器会为特定的源代码行创建额外的字节码。这种情况可能会被 JaCoCo/EclEmma 的未来版本过滤掉。

按照文章中的链接,您将转到 Jacoco 的 GH 站点上的FilteringOptions页面,其中提到了 JDK 可能生成代码的多种方式,这些代码将触发这些“虚假”代码覆盖警告。

然而,这不是这里的作用(或不完全是)。

如前所述,JaCoCo 在 Java 字节码上工作,因此编译器生成的任何不直接归因于源代码的代码都将计入覆盖范围。

在我的具体情况下,我有一个assertwhich 在源代码中代表断言发生点的分支,但也代表“全局”级别。如果您查看Foo上面定义的类的字节码(执行 a 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 的块 - 如果出现条件(如果 !assertion throw new AssertionError),则应忽略整个块

于 2013-06-10T16:58:02.233 回答
0

我也遇到了同样的问题,其中一个实用程序类显示未涵盖的类声明。(实用程序类 - 具有所有静态实用程序方法的类)。最终发现声纳意味着抱怨默认构造函数是隐式的,没有被覆盖。由于它不是用代码编写的自定义构造函数,因此声纳在类声明中显示了问题。(可能如@Adam Parkin 回答中所写,字节码在类声明的同一行有隐式构造函数,不确定)

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

于 2020-12-22T22:48:42.750 回答