eclemma branch coverage for switch: 7 of 19 missed

后端 未结 2 1951
悲&欢浪女
悲&欢浪女 2020-12-10 01:09

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 a

相关标签:
2条回答
  • 2020-12-10 01:38

    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.)

    0 讨论(0)
  • 2020-12-10 02:04

    Check out the following Link: http://sourceforge.net/p/eclemma/discussion/614869/thread/80e770df/

    Below is snippet from the above link:

    This for an example having a switch with 3 cases:

    This is quite an interesting observation. From looking at the byte code one can see how the Java compiler handles the switch on strings. Actually it is an 3-step process:

    1. Switch on the hash code (3 Branches, 1 Default)
    2. For each hash code do an equals (3 * 2 branches)
    3. Do an final switch for the actual execution of the cases (3 Branches, 1 Default)

    So we have an total of 14 branches which looks strange from the source code's point of view. What looks even more strange is that you're missing three of them. The explanation is step 2 where the equals method is applied additionally after the hash code. To cover these branches also you would need to find other strings with the same hash code. This is definitely something that might be filtered from coverage reports in future versions of JaCoCo:
    https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions

    0 讨论(0)
提交回复
热议问题