我有一个switch
从 a 中提取寻址模式的语句,String
并且我已经编写了单元测试来覆盖,我认为这是每一种可能性,但 JaCoCo 似乎跳过了我的switch
语句,导致覆盖率较低。
为什么,如果我case
的所有语句(包括默认语句)都在测试中执行,那么该switch
语句不会被视为命中?
我有一个switch
从 a 中提取寻址模式的语句,String
并且我已经编写了单元测试来覆盖,我认为这是每一种可能性,但 JaCoCo 似乎跳过了我的switch
语句,导致覆盖率较低。
为什么,如果我case
的所有语句(包括默认语句)都在测试中执行,那么该switch
语句不会被视为命中?
通过字符串切换
class Fun {
static int fun(String s) {
switch (s) {
case "I":
return 1;
case "A":
return 2;
case "Z":
return 3;
case "ABS":
return 4;
case "IND":
return 5;
default:
return 6;
}
}
}
Oracle Java 编译器生成类似于以下代码的字节码(Eclipse Compiler for Java 生成的字节码略有不同)
int c = -1;
switch (s.hashCode()) {
case 65: // +1 branch
if (s.equals("I")) // +2 branches
c = 0;
break;
case 73: // +1 branch
if (s.equals("A")) // +2 branches
c = 1;
break;
case 90: // +1 branch
if (s.equals("Z")) // +2 branches
c = 2;
break;
case 64594: // +1 branch
if (s.equals("ABS")) // +2 branches
c = 3;
break;
case 72639: // +1 branch
if (s.equals("IND")) // +2 branches
c = 4;
break;
default: // +1 branch
}
switch (c) {
case 0: // +1 branch
return 1;
case 1: // +1 branch
return 2;
case 2: // +1 branch
return 3;
case 3: // +1 branch
return 4;
case 4: // +1 branch
return 5;
default: // +1 branch
return 6;
}
因此,带有 6 个 case 的原始 switch 语句在字节码中由一个带有 6 个 case 的 switchhashCode
加上String
5 个 if 语句加上另一个带有 6 个 case 的 switch 表示。要查看此字节码,您可以使用javap -c
.
JaCoCo 执行字节码分析,并且在低于 0.8.0 的版本中没有按字符串切换的过滤器。您的测试涵盖了 if 语句中的条件评估为true
的情况,但不包括它们评估为 的情况false
。就我个人而言,我建议简单地忽略丢失的情况,因为目标不是测试编译器生成正确的代码,而是测试您的应用程序是否正确运行。但是为了这个答案的完整性 - 这里是涵盖所有字节码分支的测试:
import org.junit.Test;
import static org.junit.Assert.*;
public class FunTest {
@Test
public void test() {
// original strings:
assertEquals(1, Fun.fun("I"));
assertEquals(2, Fun.fun("A"));
assertEquals(3, Fun.fun("Z"));
assertEquals(4, Fun.fun("ABS"));
assertEquals(5, Fun.fun("IND"));
// same hash codes, but different strings:
assertEquals(6, Fun.fun("\0I"));
assertEquals(6, Fun.fun("\0A"));
assertEquals(6, Fun.fun("\0Z"));
assertEquals(6, Fun.fun("\0ABS"));
assertEquals(6, Fun.fun("\0IND"));
// distinct hash code to cover default cases of switches
assertEquals(6, Fun.fun(""));
}
}
并由 JaCoCo 0.7.9 生成的报告作为证明:
JaCoCo 0.8.0 版提供了过滤器,包括javac
为通过字符串切换生成的字节码过滤器。因此即使没有额外的测试也会生成以下报告: