Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

eclemma branch coverage for switch: 7 of 19 missed

I have this switch system and I'm using eclemma to test the branch coverage. We are required to have at least 80% in branch coverage for everything so I'm trying to test as much as possible. However, eclemma tells me this switch system is not fully tested in terms of branch coverage.

pos = p.getCurrentPosition().substring(0, 1); switch (pos) {             case "G":                 goalkeepers++;                 break;             case "D":                 defense++;                 break;             case "M":                 midfield++;                 break;             case "F":                 offense++;                 break;             case "S":                 substitutes++;                 break;             case "R":                 reserves++;                 break;         } 

I used straightforward JUnit tests to go trough each of these cases. Still eclemma marks this as yellow and says "7 of 19 branches missed". I would say there are only 7 ways to go through this switch system (the 6 individual cases+all undefined).

I tried searching for similar questions on stack overflow. Some of them had as solutions to use if/else for full coverage. I'm not sure if this is the only way possible to get this coverage.

Can anybody explain where all these 19 branches come from and how I could test these remaining 7 to get a 100% branch coverage on this switch case?

like image 798
Gaargod Avatar asked Jan 18 '15 19:01

Gaargod


People also ask

How do I cover branch code coverage?

To calculate Branch Coverage, one has to find out the minimum number of paths which will ensure that all the edges are covered. In this case there is no single path which will ensure coverage of all the edges at once. The aim is to cover all possible true/false decisions.

What should be the branch coverage?

Branch coverage is a requirement that, for each branch in the program (e.g., if statements, loops), each branch have been executed at least once during testing. (It is sometimes also described as saying that each branch condition must have been true at least once and false at least once during testing.)

What is branch in code coverage?

Branch coverage is a metric that indicates whether all branches in a codebase are exercised by tests. A "branch" is one of the possible execution paths the code can take after a decision statement—e.g., an if statement—gets evaluated.

How does JaCoCo calculate branch coverage?

JaCoCo also calculates branch coverage for all if and switch statements. This metric counts the total number of such branches in a method and determines the number of executed or missed branches. Branch coverage is always available, even in absence of debug information in the class files.


1 Answers

The Java compiler translates the switch-case code either to a tableswitch or to a lookupswitch. The tableswitch is used when there are only a few gaps are between the different cases. Otherwise, the lookupswitch is used.

In your case a tableswitch is used because the hash codes of your cases are closely spaced (unlike in the code referenced by owaism):

  16: tableswitch   { // 68 to 83                 68: 111 // 'D'                 69: 183                 70: 141 // 'F'                 71: 96  // 'G'                 72: 183                 73: 183                 74: 183                 75: 183                 76: 183                 77: 126 // 'M'                 78: 183                 79: 183                 80: 183                 81: 183                 82: 171 // 'R'                 83: 156 // 'S'            default: 183       } 

The numbers to the left of the colon are the ordered hash codes and the filled gaps between them, the numbers to the right are the jump destinations. (In Java, the hash code of a character is its ASCII value.)

68 is the hash code of "D" (the lowest one), and 83 is the hash code of "S" (the highest one). 69 is the value of one of the gaps between the real cases and will jump to the default case.

However, I assume that EclEmma excludes these branches from the coverage computation of a tableswitch (it would lower the coverage even more because of the gaps). So we have 0 (counted) branches yet.

Next, an equals comparison of the string value is performed at each jump destination (except at the one of the default case). As your switch-case consists of 6 cases, we have 6 six jump destinations with an equals comparison.

The byte code of the comparison for case "G" is below:

  96: aload_3   97: ldc           #10   99: invokevirtual #11  java/lang/Object;)Z  102: ifeq          183  105: iconst_0  106: istore        4  108: goto          183  111: aload_3 

EclEmma counts two branches: either the input string and the case string are equals or they are not. Thus, we have 6 * 2 branches for the comparisons. (The default case does not branch.)

Next, if the two strings are equal the index of the case will be stored (byte code lines 105-106 for the case "G"). Then a jump to the second tableswitch will be executed. Otherwise, the jump will be executed directly.

 185: tableswitch   { // 0 to 5                  0: 224                  1: 237                  2: 250                  3: 263                  4: 276                  5: 289            default: 299       } 

This switch operates on the previously stored case index and jumps to the code in the case (case "G" has index 0, the default case has -1). EclEmma counts 7 branches (6 cases plus the default case).

Consequently, we have 0 counted branches in the first tableswitch, 12 branches in the equals comparisons and further 7 branches in the second tableswitch. All in all, this results in 19 branches.


Your tests do not cover any of the 6 not-equals branches. In order to cover these, you would need to find a string for each case which is not equal to the case condition but has the same hash code. It is possible, but definitively not sensible...

Probably, the branch counting of EclEmma will be adjusted in the future.

Moreover, I guess you don't have a test case which does not match with any of the cases (thus the (implicit) default case is not covered.)

like image 141
nrainer Avatar answered Oct 04 '22 07:10

nrainer