Coverage of sonar branches in class declaration

I have a class in Sonar:

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

And Sonar reports half the branches covered by this public class Foo . What does it mean? How do you check a string declaring a class?

Edit: in case it matters, this is Sonar v3.5.

Edit 2: Screenshot showing what I mean, look at 1/2 next to the “public class” on line 9. When I hover over it, I get a hint that says “1 branches are covered by tests”

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

Edit # 3: Okay, a little more investigation, I narrowed it down to the smallest snippet I can find that causes this:

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

If this statement does not exist in the constructor, the "N / 2 branch coated" flag is not generated in Sonar. If the statement disappears, the flag also disappears. So I assume it is based on branches inside the constructor? (this code has 0/4 branches for the assert line and 0/2 for the public class line).

+6
source share
1 answer

This seems to be a problem with the JaCoCo Sonar code coverage component. JaCoCo works with compiled bytecode, not a Java source, and the Java compiler can generate code that is not directly related to the source source.

Looking at the docs for JaCoCo, there is a section that reads (highlighted by me):

In some situations, it is not obvious why individual lines have a highlight or a certain color. The reason is that the JaCoCo base code coverage library only works with Java class files. In some cases, the Java compiler generates extra byte code for a particular line of source code . Such situations may be filtered out in future versions of JaCoCo / EclEmma.

By following the link in the passage, you will be taken to the FilteringOptions page on the Jacoco GH website, and it mentions a number of ways that the JDK can create code that will trigger these “false” warnings about code coverage.

However, this is not what is played here (or not quite).

As already mentioned, JaCoCo runs on Java bytecode, so any code that is generated by the compiler that is not directly bound to the source will be considered for coverage.

In my particular case, I had an assert , which in the source is a branch at the point where the statement occurs, but also at the "global" level. If you look at the bytecode for the Foo class defined above (do a javap -c Foo ), you will see:

 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 7 line, which is a conditional branch depending on whether statements are included. Thus, if you have a class with a simple Java assert in it, you will have this branch somewhere in the bytecode, and this is what leads to a warning about the coverage of "N / 2 branches" in the class declaration, where N is either 0 or 1, depending on when the class was ever executed as a result of the test (1) or not (0).

Edit: note that this is also mentioned in https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions :

Blocks that throw AssertionErrors - the entire block should be ignored if the condition (if! Assertion throw new AssertionError)

+7
source

Source: https://habr.com/ru/post/946790/


All Articles