开关的eclemma分支覆盖范围:19个错过了7个

时间:2015-01-18 19:14:25

标签: java testing switch-statement code-coverage eclemma

我有这个交换机系统,我正在使用eclemma来测试分支机构的覆盖范围。我们需要至少有80%的分支机构覆盖所有内容,所以我尽可能地尝试测试。 然而,eclemma告诉我,这个交换机系统在分支覆盖范围方面没有经过全面测试。

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;
        }

我使用简单的JUnit测试来解决这些问题。 仍然是eclemma将此标记为黄色并且说“错过了19个分支中的7个”。 我想说只有7种方法可以通过这个开关系统(6个个案+所有未定义)。

我尝试在堆栈溢出时搜索类似的问题。他们中的一些人使用if / else进行完全覆盖的解决方案。我不确定这是否是获得此保险的唯一途径。

任何人都可以解释所有这19个分支来自何处,以及我如何测试这些剩下的7个以获得100%的分支覆盖率?

2 个答案:

答案 0 :(得分:32)

Java编译器将switch-case代码转换为tableswitchlookupswitch。 当不同情况之间只有少量间隙时,使用tableswitch。否则,使用lookupswitch

在您的情况下使用tableswitch ,因为您的案例的哈希码间距很小(与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
      }

冒号左边的数字是有序哈希码和它们之间填充的间隙,右边的数字是跳转目的地。 (在Java中,字符的哈希码是其ASCII值。)

68是“D”(最低的)的哈希码,83是“S”的哈希码(最高的)。 69是真实案例之间差距之一的值,并将跳转到默认情况。

然而,我假设EclEmma从tableswitch的覆盖率计算中排除了这些分支(由于间隙,它会进一步降低覆盖范围)。 所以我们还有 0(计数)分支。

接下来,在每个跳转目标处执行等于字符串值的比较(除了默认情况之一)。由于您的开关案例由6个案例组成,我们有6个6个跳转目的地,并且等于比较。

案例“G”的比较字节代码如下:

  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计算两个分支:输入字符串和大小写字符串是等于或不是。因此,我们有 6 * 2分支用于比较。(默认情况下不分支。)

接下来,如果两个字符串相等,则将存储案例的索引(对于案例“G”,字节代码行105-106)。然后将执行跳转到第二个tableswitch。否则,跳转将直接执行。

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

此开关对先前存储的案例索引进行操作并跳转到案例中的代码(案例“G”具有索引0,默认情况下为-1)。 EclEmma计算 7个分支(6个案例加上默认案例)。

因此,我们在第一个tableswitch中有0个分支,在equals比较中有12个分支,在第二个tableswitch中有7个分支。总而言之,会产生19个分支。


您的测试不会覆盖6个不等分支中的任何一个。 为了覆盖这些,您需要为每种情况找到一个字符串,该字符串不等于大小写条件但具有相同的哈希码。 这是可能的,但绝对不明智......

可能会在未来调整EclEmma的分支计数。

此外,我猜你没有一个与任何情况都不匹配的测试用例(因此(隐含)默认情况不包括在内。)

答案 1 :(得分:0)

查看以下链接: http://sourceforge.net/p/eclemma/discussion/614869/thread/80e770df/

以下是上述链接的摘录:

这是一个有3个案例的开关的例子:

  

这是一个非常有趣的观察。从查看字节   代码一可以看到Java编译器如何处理字符串上的切换。   实际上这是一个分为三步的过程:

     
      
  1. 启用哈希码(3个分支,1个默认值)
  2.   
  3. 对于每个哈希码,执行等于(3 * 2个分支)
  4.   
  5. 为案例的实际执行做最后的切换(3个分支,1个默认值)
  6.         

    所以我们总共有14个分支   从源代码的角度来看很奇怪。什么看起来更多   奇怪的是你错过了其中的三个。解释是步骤   2其中在哈希码之后另外应用equals方法。   要覆盖这些分支,您还需要找到其他字符串   相同的哈希码。这绝对是可能的   在JaCoCo的未来版本中从覆盖率报告中过滤掉:
      https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions