代码覆盖率可能是最具争议的代码指标。有人说,你必须达到 80% 的代码覆盖率,有人说,这是肤浅的,并没有说明你的测试质量。(请参阅Jon Limjap 关于“单元测试的合理代码覆盖率是多少(以及为什么)?”的好回答。)
人们倾向于衡量一切。他们需要比较、基准等。
项目团队需要一个指针,他们的测试有多好。
那么代码覆盖率的替代方案是什么?有什么比“我触摸了这行代码”更能说明问题的好指标?
有真正的替代品吗?
代码覆盖率可能是最具争议的代码指标。有人说,你必须达到 80% 的代码覆盖率,有人说,这是肤浅的,并没有说明你的测试质量。(请参阅Jon Limjap 关于“单元测试的合理代码覆盖率是多少(以及为什么)?”的好回答。)
人们倾向于衡量一切。他们需要比较、基准等。
项目团队需要一个指针,他们的测试有多好。
那么代码覆盖率的替代方案是什么?有什么比“我触摸了这行代码”更能说明问题的好指标?
有真正的替代品吗?
如果您正在寻找一些有用的指标来告诉您代码的质量(或缺乏质量),您应该查看以下指标:
这些只是 NDepend(一个 .NET 指标和依赖关系映射实用程序)可以为您提供的一些关键指标。我最近在代码指标方面做了很多工作,这 4 个指标是我们发现最有用的核心关键指标。然而,NDepend 提供了一些其他有用的指标,包括传出和传入耦合以及抽象性和不稳定性,它们结合起来提供了一个很好的衡量标准,可以衡量您的代码的可维护性(以及您是否处于 NDepend 所称的痛苦区域或痛苦区域)无用。)
即使您不使用 .NET 平台,我也建议您查看NDepend 指标页面。那里有很多有用的信息,您可以使用它们在您开发的任何平台上计算这些指标。
Crap4j是我知道的一个相当不错的指标......
它是变更风险分析和预测软件度量的 Java 实现,它结合了自动化测试的圈复杂度和代码覆盖率。
错误指标也很重要:
例如,检测错误是否没有像新出现的那样快速解决。
代码覆盖率只是一个指标,有助于指出测试中根本没有执行的行,这很有趣。如果您达到 80% 左右的代码覆盖率,那么查看剩余 20% 的行以确定您是否缺少某些用例就开始有意义了。如果你看到“啊哈,如果我传递一个空向量,这条线就会被执行”,那么你实际上可以编写一个传递一个空向量的测试。
作为我能想到的替代方案,如果你有一个包含用例和功能需求的规范文档,你应该将单元测试映射到它们,看看有多少 UC 被 FR 覆盖(当然应该是 100%)以及有多少FR 被 UT 覆盖(同样,它应该是 100%)。
如果你没有规格,谁在乎?发生任何事情都会好的:)
在你的项目中观察代码覆盖率的趋势怎么样?
与许多其他指标一样,单个数字并不能说明太多。
例如,如果“我们的 Checkstyle 规则合规率为 78.765432%”,就很难判断是否存在问题。如果昨天的合规率是100%,我们肯定有麻烦了。如果昨天是 50%,我们可能做得很好。
当代码覆盖率随着时间的推移越来越低时,我总是会感到紧张。在某些情况下这是可以的,因此您在查看图表和数字时不能转过头来。
顺便说一句,声纳(http://sonar.codehaus.org/)是观察趋势的好工具。
单独使用代码覆盖率几乎没有意义,只有在您寻找不必要的代码时,它才能让您深入了解。
将它与单元测试一起使用并以 100% 的覆盖率为目标将告诉您所有“测试”部分(假设它也全部成功)按照单元测试中的规定工作。
从技术设计/功能设计编写单元测试,具有 100% 的覆盖率和 100% 成功的测试将告诉您该程序的工作方式与文档中描述的一样。
现在你唯一需要的是好的文档,尤其是功能设计,程序员不应该写那些,除非他是那个特定领域的专家。
(代码行数)/(测试用例数)怎么样?不是很有意义(因为它取决于 LOC),但至少它很容易计算。
另一个可能是(测试用例数)/(方法数)。
根据经验,缺陷注入率与代码良率成比例,它们通常都遵循瑞利分布曲线。
在某个时候,您的缺陷检测率将达到峰值,然后开始下降。
该顶点代表 40% 的已发现缺陷。
继续进行简单的回归分析,您可以估计在峰值之后的任何时间点您的产品中仍有多少缺陷。
这是 Lawrence Putnam 模型的一个组成部分。
场景覆盖。
我不认为你真的想要 100% 的代码覆盖率。测试说,简单的 getter 和 setter 看起来是在浪费时间。
代码总是在某些上下文中运行,因此您可以列出尽可能多的场景(取决于问题的复杂性,有时甚至是所有场景)并测试它们。
例子:
// parses a line from .ini configuration file
// e.g. in the form of name=value1,value2
List parseConfig(string setting)
{
(name, values) = split_string_to_name_and_values(setting, '=')
values_list = split_values(values, ',')
return values_list
}
现在,您有许多场景需要测试。他们中有一些:
传递正确的值
项目清单
传递空值
传递空字符串
传递格式错误的参数
以逗号开头或结尾传递字符串,例如 name=value1 或 name=,value2
仅运行第一个测试可能会给您(取决于代码)100% 的代码覆盖率。但是你没有考虑所有的可能性,所以这个指标本身并不能告诉你太多。
我写了一篇关于为什么高测试覆盖率无论如何都是一件好事的博客文章。
我同意:当测试执行一部分代码时,并不意味着这部分代码产生的结果的有效性经过测试验证。
但是,如果您在测试执行期间大量使用合约来检查状态的有效性,那么高测试覆盖率将意味着大量的验证。
代码覆盖率的价值在于它可以让您对测试执行的内容有所了解。短语“代码覆盖率”通常用于表示语句覆盖率,例如“我的代码(以行数)已经执行了多少”,但实际上“覆盖率”有一百多种。这些其他版本的覆盖试图提供一个更复杂的视图,即练习代码意味着什么。
例如,条件覆盖率测量有多少条件表达式的单独元素已被执行。这与语句覆盖率不同。MC/DC“修改条件/决策覆盖”确定所有条件表达式的元素是否都已被证明来控制条件的结果,并且是 FAA 对飞行器软件的要求。路径覆盖率衡量通过你的代码有多少可能的执行路径已经被执行。这比语句覆盖率更好,因为路径本质上代表代码中的不同情况。最好使用这些措施中的哪一个取决于您对测试有效性的关注程度。
Wikipedia 相当好地讨论了测试覆盖率的许多变体。 http://en.wikipedia.org/wiki/Code_coverage
这一点没有被提及,但是给定代码或方法文件中的更改量(通过查看版本控制历史)很有趣,特别是当您为测试不佳的代码构建测试套件时。将您的测试集中在您更改很多的代码部分上。把那些你不喜欢的留到以后。
当心因果颠倒。您可能会避免更改未经测试的代码,并且您可能倾向于更多地更改经过测试的代码。
SQLite 是一个经过严格测试的库,您可以从中提取各种指标。
从 3.6.14 版开始(报告中的所有统计数据均针对该版本的 SQLite),SQLite 库由大约 63.2 KSLOC 的 C 代码组成。(KSLOC 的意思是数千个“源代码行”,或者换句话说,不包括空白行和注释的代码行。)相比之下,该项目的测试代码和测试脚本是 715 倍 - 45261.5 KSLOC。
最后,最让我印象深刻的是,这些可能的指标似乎没有一个比简单的陈述更重要,“它满足所有要求”。(所以在实现它的过程中不要忽视这个目标。)
如果你想用一些东西来判断一个团队的进步,那么你就必须提出个人要求。这给了你一些东西可以指向并说“这个完成了,这个没有”。它不是线性的(解决每个需求都需要不同的工作),并且可以线性化它的唯一方法是问题已经在其他地方解决(因此您可以量化每个需求的工作)。
我喜欢收入、销售数字、利润。它们是代码库的非常好的指标。
可能不仅要衡量单元测试覆盖(触及)的代码,还要衡量断言的好坏。
一个易于实施的指标是衡量Assert.AreEqual
您可以创建自己的 Assert 实现,调用Assert.AreEqual
和测量作为第二个参数传递的对象的大小。