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

我有这个交换机系统,我正在使用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%的分支覆盖率?

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

在你的情况下使用tableswitch因为你的case的哈希码是紧密间隔的(与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从表格开关的覆盖计算中排除了这些分支(由于间隙,它会进一步降低覆盖范围)。 所以我们还有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的分支计数将在未来进行调整。

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

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

以下是上述链接的摘录:

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

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

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

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