对于依赖于 Java 中的东西的未覆盖代码,SonarQube 新代码覆盖率的质量门失败 [英] SonarQube quality gate on new code coverage fails for uncovered code that relies on things baked into Java
问题描述
我们团队中有人更改了此代码:
Someone on our team changed this code:
public class Rectangle implements Cloneable, Serializable {
@Override
public Rectangle clone() {
return new Rectangle(x, y, width, height);
}
}
到这个代码:
public class Rectangle implements Cloneable, Serializable {
@Override
public Rectangle clone() {
try {
// super.clone is safe to return since all of the Rectangle's fields are primitive.
return (Rectangle) super.clone();
} catch (CloneNotSupportedException e) {
// should never happen since Cloneable is implemented
return null;
}
}
}
他们编写了一个单元测试,涵盖了 try
代码路径.
They wrote a unit test that covers the try
code path.
他们没有编写涵盖 catch
代码路径的测试.catch
代码路径依赖于烘焙"到 Java 中的东西,使其崩溃的唯一方法是通过删除 Cloneable 来更改类的结构
标记界面.但是如果该类结构发生变化,那么其他单元测试就会失败.
They did not write a test that covers the catch
code path. The catch
code path relies on things "baked" into Java, the only way to make it crash is to change the structure of the class, by dropping the Cloneable
marker interface. But if that class structure changes, then the other unit test should fail.
因为 catch
代码路径没有被单元测试覆盖,所以 SonarQube 质量门新代码的代码覆盖率"失败,并且因为质量门失败,构建它的 Jenkins 作业分支失败,并且由于 Jenkins 作业失败,Bitbucket 将不允许合并.
Because the catch
code path isn't covered by a unit test, the SonarQube quality gate "code coverage on new code" fails, and because the quality gate fails, the Jenkins job that builds that branch fails, and because the Jenkins job fails, Bitbucket won't allow the merge.
已经尝试过:
- 失败:在 SonarQube 中标记为误报:代码覆盖质量门不可能,您只能针对基于规则的问题执行此操作.
- DIRTY HACK:在运行作业之前关闭(或降低)SonarQube 中的质量门限,并在分支合并后重新打开它:这可行,但感觉太脏了,我认为它应该发生得非常异常.我正在寻找一种不需要人工干预的更好的解决方案.
- 失败:模拟
Rectangle
:不起作用,super.clone()
必须被模拟,在Object.clone()
,这是一个受保护的方法. - FAILED:通过增加一个类来伪造它,例如
Rectangle
->EvilRectangle
->TestRectangle
,其中EvilRectangle
抛出CloneNotSupportedException
然后TestRectangle
是为测试实例化的实际类.不会工作,因为这会改变clone()
方法的签名,它不会在Rectangle
中抛出CloneNotSupportedException
.
- FAILED: Mark as false positive in SonarQube: not possible for code coverage quality gate, you can only do that for rule-based issues.
- DIRTY HACK: Turn off (or lower) the quality gate in SonarQube before running the job, and turning it back on after the branch is merged: this works, but it feels so dirty that I think it should happen really exceptionally. I'm looking for a better solution that doesn't require a manual intervention.
- FAILED: Mocking
Rectangle
: won't work,super.clone()
would have to be mocked, which is onObject.clone()
, which is a protected method. - FAILED: Fake it by having an additional class, e.g.
Rectangle
->EvilRectangle
->TestRectangle
, whereEvilRectangle
throws theCloneNotSupportedException
and thenTestRectangle
is the actual class instantiated for the test. Won't work because that would change the signature of theclone()
method, it doesn't throwCloneNotSupportedException
inRectangle
.
问题
- Java 人员:
- 如何为
catch
代码路径编写单元测试? - 如何在不更改其公共 API 的情况下重写代码,使其变得可测试?
- SonarQube 人员
- 如何通过质量门新代码的代码覆盖率"?
- Java people:
- How does one write a unit test for the
catch
code path? - How can the code be rewritten, without changing it's public API, so that it becomes testable?
- SonarQube people
- How does one make the quality gate "code coverage on new code" pass?
编辑历史
- 添加了原始代码
推荐答案
Apache Commons Lang 提供了一个 clone
方法,该方法进行深度复制并且不抛出异常.没有例外意味着不需要 try/catch
,因此测试的代码路径减少了.我在一篇讨论 Object.clone()
替代方案的文章中发现了这一点:https://dzone.com/articles/java-cloning-copy-constructor-vs-cloning
Apache Commons Lang provides a clone
method that does a deep copy and does not throw an exception. No exception means no try/catch
needed, thus one less code path to test. I found this in an article discussing alternatives for Object.clone()
: https://dzone.com/articles/java-cloning-copy-constructor-vs-cloning
将此添加到pom.xml
:
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
将此添加到您的类的导入语句中:
Add this to the import statements of your class:
import org.apache.commons.lang.SerializationUtils;
您的类必须具有实现可序列化
.添加一个private static final long serialVersionUID
,这显然是一个最佳实践.
Your class must have implements Serializable
. Add a private static final long serialVersionUID
, that's apparently a best practice.
然后将 super.clone()
替换为 SerializationUtils.clone(this)
.
最后,您可以删除 clone()
语句周围的 try/catch
,或从方法中删除 trows
.
And finally, you can remove the try/catch
around the clone()
statement, or remove the trows
from the method.
这是我的新代码:
@Override
public Rectangle clone() {
return (Rectangle) SerializationUtils.clone(this);
}
之前的单元测试已经覆盖了它,并且该单元测试仍然通过.
It was already covered by a unit test from before, and that unit test still passes.
这篇关于对于依赖于 Java 中的东西的未覆盖代码,SonarQube 新代码覆盖率的质量门失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!