Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is JaCoCo not covering my String switch statements?

I have a switch statement that extracts an addressing mode from a String and I've written unit tests to cover, what I thought was every eventuality but JaCoCo seems to skip my switch statements, resulting in lower coverage.

Why, if all my case statements, including a default are being executed in tests, would the switch statement not be counted as hit?

enter image description here

like image 443
Ross Drew Avatar asked Mar 07 '17 07:03

Ross Drew


People also ask

Can you use switch statements for strings?

Yes, we can use a switch statement with Strings in Java.

How does JaCoCo determine coverage?

JaCoCo mainly provides three important metrics: Lines coverage reflects the amount of code that has been exercised based on the number of Java byte code instructions called by the tests. Branches coverage shows the percent of exercised branches in the code, typically related to if/else and switch statements.

Does Return break a switch Java?

Return Inside switch Because a return ends execution of that method, there is no risk to fall through and hence no need for break .

Why do code lines with exceptions show no coverage in JaCoCo?

Source code lines with exceptions show no coverage. Why? JaCoCo determines code execution with so called probes. Probes are inserted into the control flow at certain positions. Code is considered as executed when a subsequent probe has been executed.

What is JaCoCo coverage in Java?

Code coverage is a software metric used to measure how many lines of our code are executed during automated tests. In this tutorial, we're going to stroll through some practical aspects of using JaCoCo, a code coverage reports generator for Java projects. 2. Maven Configuration

How to achieve 100% code coverage in Maven with JaCoCo?

In order to achieve 100% code coverage, we need to introduce tests that cover the missing parts shown in the initial report: Now we have enough tests to cover our the entire code, but to make sure of that, let's run the Maven command mvn jacoco:report to publish the coverage report:

What does JaCoCo see when method Inin fail?

In fail (Supplier) JaCoCo only sees a method invocation. Sorry, something went wrong. already existing improvement for the case of exceptions ( #310) does not cover this case unfortunately, since it marks lines above the line with call of method that throws exception. So I've been thinking about further improvements.


Video Answer


1 Answers

For the switch by String

class Fun  {
  static int fun(String s) {
    switch (s) {
      case "I":
        return 1;
      case "A":
        return 2;
      case "Z":
        return 3;
      case "ABS":
        return 4;
      case "IND":
        return 5;
      default:
        return 6;
    }
  }
}

Oracle Java compiler generates bytecode similar to the following code (Eclipse Compiler for Java generates slightly different bytecode)

    int c = -1;
    switch (s.hashCode()) {
      case 65: // +1 branch
        if (s.equals("I")) // +2 branches
          c = 0;
        break;
      case 73: // +1 branch
        if (s.equals("A")) // +2 branches
          c = 1;
        break;
      case 90: // +1 branch
        if (s.equals("Z")) // +2 branches
          c = 2;
        break;
      case 64594: // +1 branch
        if (s.equals("ABS")) // +2 branches
          c = 3;
        break;
      case 72639: // +1 branch
        if (s.equals("IND")) // +2 branches
          c = 4;
        break;
      default: // +1 branch
    }
    switch (c) {
      case 0: // +1 branch
        return 1;
      case 1: // +1 branch
        return 2;
      case 2: // +1 branch
        return 3;
      case 3: // +1 branch
        return 4;
      case 4: // +1 branch
        return 5;
      default: // +1 branch
        return 6;
    }

So that original switch-statement with 6 cases is represented in bytecode by a switch with 6 cases for hashCode of String plus 5 if-statements plus another switch with 6 cases. To see this bytecode you can use javap -c.

JaCoCo performs analysis of bytecode and in versions lower than 0.8.0 has no filter for switch by string. Your tests cover cases, where conditions in if-statements evaluate to true, but not the cases where they evaluate to false. Personally I would advise to simply ignore missing cases, because the goal is not to test that compiler generates proper code, but to test that your application behaves correctly. But for a sake of completeness of this answer - here is tests that cover all bytecode branches:

import org.junit.Test;
import static org.junit.Assert.*;

public class FunTest {
  @Test
  public void test() {
    // original strings:
    assertEquals(1, Fun.fun("I"));
    assertEquals(2, Fun.fun("A"));
    assertEquals(3, Fun.fun("Z"));
    assertEquals(4, Fun.fun("ABS"));
    assertEquals(5, Fun.fun("IND"));

    // same hash codes, but different strings:
    assertEquals(6, Fun.fun("\0I"));
    assertEquals(6, Fun.fun("\0A"));
    assertEquals(6, Fun.fun("\0Z"));
    assertEquals(6, Fun.fun("\0ABS"));
    assertEquals(6, Fun.fun("\0IND"));

    // distinct hash code to cover default cases of switches
    assertEquals(6, Fun.fun(""));
  }
}

And report generated by JaCoCo 0.7.9 as a proof:

coverage report

JaCoCo version 0.8.0 provides filters, including filter for bytecode that javac produces for switch by string. And so generates following report even without additional tests:

coverage report

like image 136
Godin Avatar answered Oct 29 '22 16:10

Godin