彩票走势图

JUnit代码覆盖率和自动测试用例生成

原创|使用教程|编辑:郑恭琳|2021-01-07 11:05:38.350|阅读 447 次

概述:如果代码覆盖率对您来说是个问题,请确保您对其进行了正确测量,并从您运行的所有测试中对其进行了测量。利用自动JUnit代码覆盖率测试用例生成来快速构建和扩展测试,以获得有意义的、可维护的完整代码覆盖率。单元测试覆盖率是确保您正确测量所有内容的好方法。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

相关链接:

如果代码覆盖率对您来说是个问题,请确保您对其进行了正确测量,并从您运行的所有测试中对其进行了测量。利用自动JUnit代码覆盖率测试用例生成来快速构建和扩展测试,以获得有意义的、可维护的完整代码覆盖率。单元测试覆盖率是确保您正确测量所有内容的好方法。

我最近写了一篇关于陷入代码覆盖率百分比陷阱的讨论,这引发了质量讨论,所以我想我将更深入地探讨代码覆盖率问题和解决方案。具体来说,涵盖本身,自动生成的JUnit测试的值以及如何识别有问题的单元测试。以及如何在执行方面继续做得更好。


JUnit代码覆盖率如何工作?

让我们从覆盖率指标本身以及我们如何计算代码覆盖率开始。代码覆盖率数字通常是无意义的,或充其量是误导的。如果您“确实”拥有100%的代码覆盖率,那又意味着什么?您是如何测量的?

有很多不同的方法来衡量覆盖率。

衡量代码覆盖率的一种方法是从需求角度出发。您是否对每一项要求都进行了测试?这是一个合理的开始……但这并不意味着所有代码都已经过测试。

衡量代码覆盖率的另一种方法(别笑,我实际上是在现实世界中听到的)是通过测试的次数。真的,我是真的!这是一个非常糟糕的指标,显然毫无意义。是比简单地计算您拥有多少个测试还差?我不能说。

然后我们来尝试确定执行了什么代码。常见的覆盖率指标包括语句覆盖率、行覆盖率、分支覆盖率、决策覆盖率、多个条件覆盖率,或者更全面的MC/DC或修改后的条件/决策覆盖率。

当然,最简单的方法是线路覆盖率,但是您可能已经看到,工具对此进行了不同的衡量,因此覆盖率将有所不同。执行代码行并不意味着您已经检查了该代码行中可能发生的所有不同情况。这就是为什么安全关键标准(例如用于汽车功能安全的ISO 26262和用于机载系统的DO-178B/C)都需要MC/DC

这是一个简单的代码示例,假设xyz为布尔值:

If ( (x||y) && z) { doSomethingGood(); } else {doSomethingElse();}

在这种情况下,无论我的值是多少,该行都被“覆盖”了。诚然,这是一种将所有内容都放在一行上的草率方法,但是您看到了问题。人们实际上以这种方式编写代码。但是,让我们整理一下。

If ( (x||y) && z) {
doSomethingGood();
} else {
doSomethingElse(); /* because code should never doSomethingBad() */

一目了然,我可能会得出这样的结论:我只需要两个测试——一个将整个表达式评估为TRUE并执行doSomethingGood() (x=true, y=true, z=true),而另一个则评估为FALSE并执行doSomethingElse() (x=false, y=false, z=false)行覆盖率说我们很高兴,“一切都经过测试。”

但是请稍等,可以通过多种方式测试主表达式:

这是一个简单的示例,但它说明了这一点。我这里需要进行4个测试才能真正正确地覆盖代码,至少在我关心MC/DC覆盖率的情况下。当我完成一半时,行覆盖率会说100%。我将再一次不再详细说明MC/DC的价值。这里的重点是,无论您使用哪种方法衡量覆盖率,通过断言进行验证的内容都有意义是很重要的。


无意义的自动生成

许多人陷入的另一个陷阱是添加了一种不复杂的工具来自动生成单元测试。

简单的测试生成工具可以创建无需任何声明即可执行代码的测试。这样可以避免测试变得嘈杂,但实际上意味着您的应用程序不会崩溃。不幸的是,这并不能告诉您应用程序是否在执行应做的事情,这很重要。

下一代工具通过根据它们可以自动捕获的任何特定值创建断言来工作。但是,如果自动生成会产生大量断言,则最终会产生大量麻烦。这里没有中间立场。您要么拥有易于维护但毫无意义的东西,要么拥有值得怀疑的维护噩梦。

首先,许多自动生成单元测试的开源工具看起来很有价值,因为您的覆盖率非常快。真正的问题在于维护。通常,在开发过程中,开发人员会付出额外的努力来微调自动生成的断言,以创建他们认为干净的测试套件。但是,断言是脆弱的,不能随着代码的更改而适应。这意味着开发人员在下次发布时必须再次执行大部分“自动”生成。测试套件可以重用。如果您无法重复使用它们,则说明您做错了什么。

这也不能掩盖一个可怕的想法,即在第一次运行时,当您具有较高的覆盖率时,测试中的断言没有应有的意义。仅仅因为可以断言某些东西,并不意味着应该这样做,或者甚至是正确的事情。

public class ListTest {
private List<String> list = new ArrayList<>();
@Test
public void testAdd() {
list.add(“Foo”);
assertNotNull(list);
}
}

理想情况下,断言将检查代码是否正常运行,并且当代码工作不正常时,断言将失败。有很多断言都不是很容易的,我们将在下面进行探讨。


原始覆盖率与有意义的测试

如果您要以覆盖率高、可靠、干净的测试套件为代价来拍摄高覆盖率的产品,那么您将失去价值。一套维护良好的测试套件使您对代码充满信心,甚至是快速安全重构的基础。嘈杂和/或毫无意义的测试意味着您不能依赖测试套件,不能重构,甚至不能发布。

人们对代码进行衡量(尤其是根据严格的标准)时,会发现他们发现自己的代码比自己想要的要低。通常,这最终导致他们追逐承保率。让我们开始报道吧!现在,您可能会因为不合理的信念而陷入危险的境地,即自动化JUnit测试已经创建了有意义的测试,或者通过手工创建了意义不大且维护成本很高的单元测试。

在现实世界中,维护测试套件的持续成本远远超过了创建单元测试的成本,因此从一开始就创建良好的干净单元测试非常重要。您会知道这一点,因为您可以在持续集成(CI)流程中始终运行测试。如果您仅在发行时运行测试,则表明测试噪音大。具有讽刺意味的是,这使得测试变得更糟,因为它们没有得到维护。

软件测试自动化还不错,实际上,这是必要的,因为它具有当今常见的复杂性和时间压力。但是,自动生成价值通常比其价值更麻烦。与随意创建断言相比,基于扩展值,监视实际系统以及创建复杂的框架、模拟和存根的自动化提供了更多的价值。


你能做什么?

测量

第一步是衡量并获得有关您当前覆盖率的报告,否则,您将不会知道自己的位置以及情况是否会好转。进行此操作时,衡量所有测试活动(包括单元、功能、手册等)并正确汇总覆盖率非常重要。这样,您将尽最大的努力去努力——在完全未经测试的代码上,而不是端到端测试涵盖但没有碰巧的代码上单元测试。Parasoft可以准确地汇总来自多个运行和多种类型测试的代码覆盖率,从而为您提供准确的位置信息。有关此方面的更多信息,请参见我们的白皮书:全面的代码覆盖—测试实践的合计覆盖率

构架

为您创建单元测试框架的工具是一个很好的入门方法。确保这些工具连接到MockitoPowerMock等常见的模拟框架,因为实际代码很复杂,并且需要存根和模拟。但这还不够,您需要能够:

  • 创建有意义的模拟
  • 使用更大、更广泛的数据扩展简单的测试
  • 监视正在运行的应用程序


智能协助

您可以手动完成所有这些操作,但是这会花费大量时间和精力。这是利用自动化的绝佳场所——例如,Parasoft JtestIDE中实时提供自动建议,并与开源框架(JUnitMockitoPowerMock等)集成,以帮助用户创建扩展和维护他们的JUnit测试套件并提供更广泛的覆盖率。如果您对此技术感到好奇,则可以了解有关人们为什么讨厌单元测试又如何重新喜爱上它的更多信息。


总结

如果覆盖率对于您的项目来说是一个问题,请确保您对其进行了正确的衡量,并从您运行的所有测试中对所有方面进行了衡量。随着您开始使用单元测试扩展覆盖率,您可以利用指导性的测试创建来快速创建和扩展测试,以获取有意义的可维护代码覆盖率。Parasoft Jtest将创建随着代码的增长和更改而可维护的测试,因此您不必一遍又一遍地执行相同的工作。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP