英文:
Jacoco code coverage: non-existent Static block shows only 75% coverage
问题
在类BrickSortParallel中有两个静态方法。它们都被单元测试完全覆盖。但是我有一个静态块static {...}
,在Jacoco的代码覆盖率报告中只有75%的代码覆盖率。这是什么意思?
以下是测试上述方法以确保完全代码覆盖的测试用例:
测试类为ComputeTaskCountTest:
class ComputeTaskCountTest {
// ... 这里是测试方法的定义 ...
}
我在上述测试类中有遗漏了什么吗?
完整的类代码位于以下链接:
您提供的Java版本是:
openjdk 11.0.8 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10)
OpenJDK 64-Bit Server VM (build 11.0.8+10, mixed mode)
Jacoco版本:0.85
从报告中可以看出,静态块的圈复杂度为2,只有一个分支被覆盖,这意味着还缺少一个测试用例来覆盖这种情况。
英文:
I have two static methods in the class BrickSortParallel. They are fully covered by unit tests. But I have a static block static {...}
listed with only 75% code coverage by Jacoco. What does that signify?
public static int computeOddTaskCount(int length) {
if (length < 0) throw new IllegalArgumentException("Illegal argument value: " + length);
return isOdd(length) ? length >> 1 : abs(length - 1) >> 1;
}
public static int computeEvenTaskCount(int length) {
if (length < 0) throw new IllegalArgumentException("Illegal argument value: " + length);
return length >> 1;
}
Following are test cases to ensure full code coverage for above methods:
class ComputeTaskCountTest {
private static final String ZERO_TASKS_EXPECTED = "Zero tasks expected.";
private static final String ONE_TASK_EXPECTED = "One task expected.";
private static final String HALF_TASKS_EXPECTED = "Half tasks expected.";
private static final String ILLEGAL_LENGTH_EXPECTED = "Illegal length expected.";
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testZeroLength")
void testZeroLength() {
assertEquals(0, computeOddTaskCount(0), ZERO_TASKS_EXPECTED);
assertEquals(0, computeEvenTaskCount(0), ZERO_TASKS_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testMinusOneLength")
void testMinusOneLength() {
assertThrows(
IllegalArgumentException.class, () -> computeOddTaskCount(-1), ILLEGAL_LENGTH_EXPECTED);
assertThrows(
IllegalArgumentException.class, () -> computeEvenTaskCount(-1), ILLEGAL_LENGTH_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testMinusTwoLength")
void testMinusTwoLength() {
assertThrows(
IllegalArgumentException.class, () -> computeOddTaskCount(-2), ILLEGAL_LENGTH_EXPECTED);
assertThrows(
IllegalArgumentException.class, () -> computeEvenTaskCount(-2), ILLEGAL_LENGTH_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testMinValueLength")
void testMinValueLength() {
assertThrows(
IllegalArgumentException.class,
() -> computeOddTaskCount(Integer.MIN_VALUE),
ILLEGAL_LENGTH_EXPECTED);
assertThrows(
IllegalArgumentException.class,
() -> computeEvenTaskCount(Integer.MIN_VALUE),
ILLEGAL_LENGTH_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testOneValueLength")
void testOneValueLength() {
assertEquals(0, computeOddTaskCount(1), ZERO_TASKS_EXPECTED);
assertEquals(0, computeEvenTaskCount(1), ZERO_TASKS_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testTwoValueLength")
void testTwoValueLength() {
assertEquals(0, computeOddTaskCount(2), ZERO_TASKS_EXPECTED);
assertEquals(1, computeEvenTaskCount(2), ONE_TASK_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testThreeValueLength")
void testThreeValueLength() {
assertEquals(1, computeOddTaskCount(3), ONE_TASK_EXPECTED);
assertEquals(1, computeEvenTaskCount(3), ONE_TASK_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testFourValueLength")
void testFourValueLength() {
assertEquals(1, computeOddTaskCount(4), ONE_TASK_EXPECTED);
assertEquals(2, computeEvenTaskCount(4), "Two tasks expected");
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testMaxValueLength")
void testMaxValueLength() {
assertEquals(
Integer.MAX_VALUE / 2, computeOddTaskCount(Integer.MAX_VALUE), HALF_TASKS_EXPECTED);
assertEquals(
Integer.MAX_VALUE / 2, computeEvenTaskCount(Integer.MAX_VALUE), HALF_TASKS_EXPECTED);
}
@Test
@DisplayName("BrickSortParallelTest.ComputeTaskCountTest.testMaxValueLengthEven")
void testMaxValueLengthEven() {
assertEquals(
(Integer.MAX_VALUE - 2) / 2,
computeOddTaskCount(Integer.MAX_VALUE - 1),
HALF_TASKS_EXPECTED);
assertEquals(
(Integer.MAX_VALUE - 1) / 2,
computeEvenTaskCount(Integer.MAX_VALUE - 1),
HALF_TASKS_EXPECTED);
}
}
Am I missing anything in the above test class?
The full classes are available at:
https://raw.githubusercontent.com/Fernal73/DSAlgos/master/src/main/java/ds/BrickSortParallel.java
$ java --version
openjdk 11.0.8 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10)
OpenJDK 64-Bit Server VM (build 11.0.8+10, mixed mode)
Jacoco version: 0.85
From the report, the static block has a cyclomatic complexity of 2 and with only one branch covered, that implies there's a test case missing to cover that eventuality.
答案1
得分: 0
引用Jacoco Github上的Marc R Hoffman的话:
“您的代码使用了assert关键字,这会导致静态初始化程序:
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #72 // class ds/BrickSortParallel
2: invokevirtual #73 // Method java/lang/Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #31 // Field $assertionsDisabled:Z
16: return
LineNumberTable:
line 19: 0
StackMapTable: number_of_entries = 2
frame_type = 12 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]
这是一个已知的限制。解决方法是不使用assert。"
以下代码片段解决了这个问题:
@Generated
private void assertEquality(int size, int count) {
if (size != count)
throw new AssertionError("Size is not the same as count.");
}
它会抛出AssertionError,但是通过@Generated
注解可以满足代码覆盖率的要求。但这仅仅是一个权宜之计。解决方案是等待Jacoco在字节码中提供所需的断言过滤。
英文:
To quote Marc R Hoffman on Jacoco Github:
"Your code uses the assert keyword which results in a static initializer:
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #72 // class ds/BrickSortParallel
2: invokevirtual #73 // Method java/lang/Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #31 // Field $assertionsDisabled:Z
16: return
LineNumberTable:
line 19: 0
StackMapTable: number_of_entries = 2
frame_type = 12 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]
This is a know limitation. The workaround is to not use assert."
The following code snippet resolves the conundrum:
@Generated
private void assertEquality(int size, int count) {
if (size != count)
throw new AssertionError("Size is not the same as count.");
}
It throws AssertionError and yet code coverage requirements are satisfied by the @Generated
annotation. It is, however, a workaround. The solution is to wait for Jacoco to provide the needed filtering of assertions in the byte code.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论