我有这个交换机系统,我正在使用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%的分支覆盖率?
答案 0 :(得分:32)
Java编译器将switch-case代码转换为tableswitch
或lookupswitch
。
当不同情况之间只有少量间隙时,使用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编译器如何处理字符串上的切换。 实际上这是一个分为三步的过程:
- 启用哈希码(3个分支,1个默认值)
- 对于每个哈希码,执行等于(3 * 2个分支)
- 为案例的实际执行做最后的切换(3个分支,1个默认值)
醇>所以我们总共有14个分支 从源代码的角度来看很奇怪。什么看起来更多 奇怪的是你错过了其中的三个。解释是步骤 2其中在哈希码之后另外应用equals方法。 要覆盖这些分支,您还需要找到其他字符串 相同的哈希码。这绝对是可能的 在JaCoCo的未来版本中从覆盖率报告中过滤掉:
https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions