SonarQube新代码覆盖率的质量门对于依赖于嵌入Java的东西的未覆盖代码来说是失败的

SonarQube新代码覆盖率的质量门对于依赖于嵌入Java的东西的未覆盖代码来说是失败的,java,unit-testing,sonarqube,Java,Unit Testing,Sonarqube,我们团队中有人更改了此代码: public class Rectangle implements Cloneable, Serializable { @Override public Rectangle clone() { return new Rectangle(x, y, width, height); } } public class Rectangle implements Cloneable, Serializable { @Ov

我们团队中有人更改了此代码:

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;
        }
    }

}
根据本守则:

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
代码路径

他们没有编写涵盖
catch
代码路径的测试。
catch
代码路径依赖于“烘焙”到Java中的东西,使其崩溃的唯一方法是通过删除
Cloneable
标记接口来更改类的结构。但是如果类结构发生变化,那么另一个单元测试应该失败

由于单元测试未覆盖
catch
代码路径,SonarQube质量门“新代码上的代码覆盖率”失败,并且由于质量门失败,构建该分支的Jenkins作业失败,并且由于Jenkins作业失败,Bitbucket将不允许合并

已尝试:

  • 失败:在SonarQube中标记为假阳性:对于代码覆盖率质量门不可能,您只能针对基于规则的问题这样做
  • 肮脏的黑客:在运行作业之前关闭(或降低)SonarQube中的质量门,并在分支合并后重新打开:这是可行的,但它感觉太脏了,我认为它应该异常地发生。我正在寻找一个不需要人工干预的更好的解决方案
  • 失败:模拟
    矩形
    :无法工作,必须模拟
    对象上的
    超级.clone()
    ,这是一种受保护的方法
  • 失败:通过使用附加类来伪造它,例如
    Rectangle
    ->
    EvilRectangle
    ->
    TestRectangle
    ,其中
    EvilRectangle
    抛出
    CloneNotSupportedException
    ,然后
    TestRectangle
    是为测试实例化的实际类。不会工作,因为这会更改
    clone()
    方法的签名,它不会在
    矩形中抛出
    CloneNotSupportedException
问题

  • 爪哇人
  • 如何为
    catch
    代码路径编写单元测试

  • 如何在不改变其公共API的情况下重写代码,使其成为可测试的
  • 成为人
  • 如何使质量门“新代码的代码覆盖率”通过
编辑历史记录

  • 添加了原始代码

Apache Commons Lang提供了一个执行深度复制且不引发异常的
克隆方法。无异常意味着不需要
try/catch
,因此要测试的代码路径少了一条。我在一篇讨论
Object.clone()
替代方案的文章中发现了这一点:

将此添加到
pom.xml

<dependency>
  <groupId>commons-lang</groupId>
  <artifactId>commons-lang</artifactId>
  <version>2.6</version>
</dependency>
类必须具有可序列化的
实现。添加一个
私有静态最终长serialVersionUID
,这显然是一个最佳实践

然后将
super.clone()
替换为
SerializationUtils.clone(this)

最后,您可以删除
clone()
语句周围的
try/catch
,或者从方法中删除
trows

这是我的新代码:

@Override
public Rectangle clone() {
    return (Rectangle) SerializationUtils.clone(this);
}

以前的单元测试已经覆盖了它,并且该单元测试仍然通过。

ApacheCommonsLang提供了一个执行深度复制且不引发异常的克隆方法。无异常意味着不需要
try/catch
,因此要测试的代码路径少了一条。我在一篇讨论
Object.clone()
替代方案的文章中发现了这一点:

将此添加到
pom.xml

<dependency>
  <groupId>commons-lang</groupId>
  <artifactId>commons-lang</artifactId>
  <version>2.6</version>
</dependency>
类必须具有可序列化的
实现。添加一个
私有静态最终长serialVersionUID
,这显然是一个最佳实践

然后将
super.clone()
替换为
SerializationUtils.clone(this)

最后,您可以删除
clone()
语句周围的
try/catch
,或者从方法中删除
trows

这是我的新代码:

@Override
public Rectangle clone() {
    return (Rectangle) SerializationUtils.clone(this);
}

以前的单元测试已经覆盖了它,但该单元测试仍然通过。

“如何在不更改其公共API的情况下重写代码,使其成为可测试的?”-不要使用
clone()
。关于原因的讨论,请参考“有效Java”。好的,谷歌搜索“有效Java不使用克隆”。如果我不明白,我会回来问更多的问题。@daniu显然“有效Java”是一本离线资源(一本书)。幸运的是,有效Java不是唯一知道为什么
clone()
是个坏主意的资源。你可以找到很多关于复制对象的问题,其中
clone()
可能是有人建议的(并且被许多其他人揭穿)。我添加了原始代码,它不包含
super.clone()
clone()
方法中。“如何在不更改其公共API的情况下重写代码,从而使其成为可测试的?”-不要使用
clone()
。有关原因的讨论,请参阅“有效Java”。好的,通过谷歌搜索“有效Java不使用克隆”。如果我不能弄清楚,我会回来问其他问题。@daniu显然是“有效Java”“是一本离线资源(一本书)。幸运的是,高效的Java并不是唯一知道为什么
clone()
只是个坏主意的资源。你可以找到很多关于复制对象的问题,其中
clone()
可能是有人建议的(并且被许多其他人揭穿)。我添加了原始代码,它不包含
super.clone()
clone()
方法中。