我有一个带有 java 版本 21 的 Spring Boot maven 多模块项目,并使用 Jacoco 版本 0.8.11 进行代码覆盖。单元测试是使用groovy编写的。
我有这样的课:
package ********************;
import lombok.Getter;
import java.util.Arrays;
@Getter
public enum SomeEnum {
VALUE1("some-value1"),
VALUE2("some-value2"),
VALUE3("some-value3");
private final String value;
private SomeEnum(String value) {
this.value = value;
}
public static SomeEnum fromValue(String value) {
if (value == null) {
return null;
}
return Arrays.stream(values())
.filter(someEnum -> someEnum.getValue().equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Invalid input value"));
}
}
这是 Groovy 测试:
package *****************************
import *********************.SomeEnum
import spock.lang.Specification
class SomeEnumTest extends Specification {
def 'test1'(String s, SomeEnum expected) {
when:
var resp = SomeEnum.fromValue(s)
then:
resp == expected
where:
s || expected
'some-value1' || SomeEnum.VALUE1
'some-value2' || SomeEnum.VALUE2
'some-value3' || SomeEnum.VALUE3
}
def 'test2'() {
when:
SomeEnum.fromValue('bs')
then:
thrown(IllegalArgumentException)
}
}
在 jacoco 的结果中,我看到这部分没有被覆盖,但它的测试存在。涵盖了构造函数和枚举值。测试成功运行。有什么问题吗?
不幸的是,这是 JaCoCo 的一个已知限制。 JaCoCo 的工作原理是在代码的不同位置注入探针(在您的示例中,在
return
之前和之后)。如果 JVM 执行探测,JaCoCo 会假设该探测之前的任何代码都已被覆盖。然而,return
或throw
语句退出函数,并且永远不会到达return
或throw
语句之后的探测。因此,JaCoCo 假设 return
/throw
尚未被覆盖。 JaCoCo 的 FAQ 有更多相关信息。
您的示例的一个特殊之处是,JaCoCo 通常至少会识别
return
语句的这种情况,因此将 return
语句标记为已覆盖,即使仅到达 return 语句之前的探测也是如此。