简体   繁体   English

声纳分支覆盖类声明

[英]Sonar branch coverage on class declaration

I have a class in Sonar:我在声纳上有一堂课:

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

And Sonar is reporting 1/2 branches covered on that public class Foo line. Sonar 报告了该public class Foo行覆盖的 1/2 分支。 What does this mean?这是什么意思? How do you test a line which declares a class?你如何测试声明一个类的行?

Edit: in case it matters, this is Sonar v3.5.编辑:以防万一,这是 Sonar v3.5。

Edit 2: A screenshot showing what I mean, note the 1/2 beside the "public class" on line 9. When hovering above this I get a tooltip stating "1 branches are covered by tests"编辑 2:显示我的意思的屏幕截图,请注意第 9 行“公共类”旁边的 1/2。当悬停在此上方时,我得到一个工具提示,说明“1 个分支被测试覆盖”

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

Edit #3: Ok, upon a bit more investigation, I've narrowed it down to smallest snippet I can find that triggers this:编辑 #3:好的,经过更多调查,我已将其范围缩小到我能找到的触发此的最小片段:

public class Foo {

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

If that assert doesn't exist in the constructor, the "N/2 branches covered" flag doesn't get generated in Sonar.如果构造函数中不存在该断言,则 Sonar 中不会生成“覆盖 N/2 个分支”标志。 If the assert is gone, then the flag goes away as well.如果断言消失了,那么标志也会消失。 So my guess is that it's based upon the branches within the constructor?所以我的猜测是它基于构造函数中的分支? (this code has 0/4 branches covered for the assert line, and 0/2 for the public class line). (此代码为 assert 行覆盖了 0/4 个分支,为公共类行覆盖了 0/2 个分支)。

It looks like this is an issue related to the JaCoCo code coverage component of Sonar.看起来这是一个与声纳的 JaCoCo 代码覆盖组件相关的问题。 JaCoCo works on compiled bytecode rather than Java source, and the Java compiler can produce code which is not directly related to the underlying source. JaCoCo 处理编译后的字节码而不是 Java 源代码,Java 编译器可以生成与底层源代码没有直接关系的代码。

Looking at the docs for JaCoCo, there's a section which reads (emphasis added):查看 JaCoCo的文档,有一个部分内容为(强调添加):

In some situations it is not obvious, why particular lines do have highlighting or have a particular color.在某些情况下,为什么特定线条确实突出显示或具有特定颜色并不明显。 The reason is that the underlying code coverage library JaCoCo works on Java class files only.原因是底层代码覆盖库 JaCoCo 仅适用于 Java 类文件。 In some cases the Java compiler creates extra byte code for a particular line of source code .在某些情况下,Java 编译器会为特定的源代码行创建额外的字节码 Such situations might be filtered by future versions of JaCoCo/EclEmma.这种情况可能会被 JaCoCo/EclEmma 的未来版本过滤掉。

Following the link in the passage takes you to the FilteringOptions page on the Jacoco's GH site, and it mentions a number of ways in which the JDK can potentially produce code which will will trigger these "spurious" code coverage warnings.按照文章中的链接,您将转到 Jacoco GH 站点上的FilteringOptions页面,其中提到了 JDK 可能会生成将触发这些“虚假”代码覆盖警告的代码的多种方式。

However, that's not what's at play here (or not exactly).然而,这不是在这里起作用的(或不完全是)。

As mentioned JaCoCo works on Java bytecode, so any code which is produced by the compiler that isn't directly attributed to the source will count towards coverage.如前所述,JaCoCo 适用于 Java 字节码,因此编译器生成的任何不直接归因于源的代码都将计入覆盖率。

In my specific case, I had an assert which, in the source, represents a branch at the point where the assert happens, but also at a "global" level.在我的特定情况下,我有一个assert ,在源代码中,它代表断言发生点的分支,但也是“全局”级别的分支。 If you look at the bytecode for the Foo class defined above (do a javap -c Foo ), you'll see:如果您查看上面定义的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

Note line 7, which is a conditional branch dependent upon whether or not assertions are enabled.注意第 7 行,这是一个条件分支,取决于断言是否启用。 Thus if you have a class with a plain Java assert in it, you'll have this branch somewhere in the bytecode, and this is what produces the "N/2 branches executed" coverage warning on the class declaration, where N is either 0 or 1 depending upon if the class was ever exercised by a test (1) or not (0).因此,如果您有一个带有普通 Java assert的类,您将在字节码中的某处有这个分支,这就是在类声明中产生“N/2 个分支执行”覆盖警告的原因,其中 N 要么是 0或 1 取决于课程是否曾通过测试 (1) 或未 (0) 进行过练习。

Edit: note that this is also mentioned inhttps://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions :编辑:请注意,https ://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions 中也提到了这一点:

Blocks that throw AssertionErrors - Entire block should be ignored if a condition (if !assertion throw new AssertionError)抛出 AssertionErrors 的块 - 如果有条件,则应忽略整个块(如果 !assertion 抛出新的 AssertionError)

I also faced this same issue where a utility class was showing class declaration as not covered.我也遇到了同样的问题,其中一个实用程序类将类声明显示为未涵盖。 (Utility class - Class with all static utility methods). (实用程序类 - 具有所有静态实用程序方法的类)。 Eventually found out that sonar meant to complain about the default constructor which is implicit, not being covered.最终发现声纳意味着抱怨默认构造函数是隐式的,没有被覆盖。 Since it is not a custom constructor written in code, sonar showed issue at the class declaration.由于它不是用代码编写的自定义构造函数,因此声纳在类声明中显示了问题。 (May be as written in @Adam Parkin answer, bytecode had implicit constructor at same line as class declaration, not sure) (可能如@Adam Parkin 的回答所写,字节码在类声明的同一行具有隐式构造函数,不确定)

Since it was utility class we never initialized object of that class in test & hence default constructor not covered.由于它是实用程序类,我们从未在测试中初始化该类的对象,因此未涵盖默认构造函数。 So I added private constructor & issue was resolved.所以我添加了私有构造函数并解决了问题。 btw sonar had also flagged code smell for private constructor.顺便说一句,声纳还标记了私有构造函数的代码异味。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM