代码覆盖率的替代指标是啥?
Posted
技术标签:
【中文标题】代码覆盖率的替代指标是啥?【英文标题】:What can be alternative metrics to code coverage?代码覆盖率的替代指标是什么? 【发布时间】:2010-11-06 01:46:14 【问题描述】:代码覆盖率可能是最具争议的代码指标。有人说,你必须达到 80% 的代码覆盖率,有人说,这是肤浅的,并没有说明你的测试质量。 (见Jon Limjap's good answer on "What is a reasonable code coverage % for unit tests (and why)?"。)
人们倾向于衡量一切。他们需要比较、基准等。 项目团队需要一个指针,他们的测试有多好。
那么代码覆盖率的替代方案是什么?还有什么比“我接触了这行代码”更能说明问题的好指标? 有真正的替代品吗?
【问题讨论】:
诚然,可接受的代码覆盖率是一个常见的争论,但我不会说这会使指标“有争议”。 @Tormod,我同意,代码覆盖率很传统——事实上,100% 的行覆盖率被认为是最低限度,不幸的是,这种情况非常罕见。 Tormod:我认为代码覆盖率并不能有效地看出项目测试的好坏。我知道其他一些开发人员也有这样的想法。所以这至少是有争议的,不是吗? 【参考方案1】:可能不仅要衡量单元测试覆盖(触及)的代码,还要衡量断言的好坏。
一个易于实施的指标是衡量Assert.AreEqual
的大小
您可以创建自己的 Assert 实现,调用 Assert.AreEqual
并测量作为第二个参数传递的对象的大小。
【讨论】:
【参考方案2】:代码覆盖率只是一个指标,有助于指出测试中根本没有执行的行,这很有趣。如果您达到 80% 左右的代码覆盖率,那么查看剩余 20% 的行以确定您是否缺少某些用例就开始有意义了。如果你看到“啊哈,如果我传递了一个空向量,这条线就会被执行”,那么你实际上可以编写一个传递一个空向量的测试。
作为替代方案,我可以想到,如果您有一个包含用例和功能需求的规范文档,您应该将单元测试映射到它们,并查看 FR 涵盖了多少 UC(当然应该是 100%)以及 UT 覆盖了多少 FR(同样,应该是 100%)。
如果您没有有规格,谁在乎?发生任何事情都会好的:)
【讨论】:
如果测试是您的规范,那么 UC/FR 覆盖率应该自动为 100%。【参考方案3】:这没有被提及,但是给定代码或方法文件中的更改量(通过查看版本控制历史)很有趣,特别是当您为测试不佳的代码构建测试套件时。将您的测试集中在您更改很多的代码部分上。把那些你不知道的留到以后。
注意因果颠倒。您可能会避免更改未经测试的代码,并且您可能倾向于更多地更改已测试的代码。
【讨论】:
【参考方案4】:根据经验,缺陷注入率与代码良率成正比,它们通常都遵循瑞利分布曲线。 在某个时候,您的缺陷检测率会达到峰值,然后开始下降。 该顶点代表 40% 的已发现缺陷。 通过简单的回归分析,您可以估计在峰值之后的任何时间点您的产品中仍有多少缺陷。 这是 Lawrence Putnam 模型的一个组成部分。
【讨论】:
这可能是一个有趣的答案,但我就是不明白。能否请您改写一下以增加可理解性? *** 只允许 600 个字符,我无法用 600 个字符详细说明这一点,所以我在一篇博文中解释了答案。请参阅redrockresearch.org/?p=58 以获得对此答案的更好解释。 感谢您的博客条目,它使它更清晰。但 40% 的数字从何而来?顺便说一句:您可以编辑您的答案以添加更多信息。【参考方案5】:代码覆盖率的价值在于它可以让您对测试执行的内容有所了解。 短语“代码覆盖率”通常用于表示语句覆盖率,例如“我的代码(以行计)执行了多少”,但实际上“覆盖率”有一百多种。这些其他版本的覆盖范围试图提供一个更复杂的视图,即练习代码意味着什么。
例如,条件覆盖率衡量有多少条件表达式的单独元素已被执行。这与语句覆盖率不同。 MC/DC “修改的条件/决策覆盖”确定所有条件表达式的元素是否都已被证明来控制条件的结果,并且是 FAA 对飞机软件的要求。路径覆盖率衡量通过你的代码有多少可能的执行路径已经被执行。这比语句覆盖率更好,因为路径本质上代表代码中的不同情况。哪种方法最适合使用取决于您对测试有效性的关注程度。
***相当好地讨论了测试覆盖率的许多变体。 http://en.wikipedia.org/wiki/Code_coverage
【讨论】:
【参考方案6】:我写了一篇关于为什么High Test Coverage Ratio is a Good Thing Anyway 的博文。
我同意:当一部分代码被测试执行时,并不意味着这部分代码产生的结果的有效性被测试验证了。
但是,如果您在测试执行期间大量使用合约来检查状态的有效性,那么高测试覆盖率将意味着大量的验证。
【讨论】:
【参考方案7】:场景覆盖。
我不认为你真的想要 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% 的代码覆盖率。但是你没有考虑所有的可能性,所以这个指标本身并不能告诉你太多。
【讨论】:
我觉得你的意思是……比如“用例覆盖率”。但这不是无法计算的指标,只有在您为每个函数定义每个场景时。【参考方案8】:我喜欢收入、销售数字和利润。它们是代码库的非常好的指标。
【讨论】:
【参考方案9】:单独使用代码覆盖率几乎没有意义,只有在您寻找不必要的代码时才能提供洞察力。
将它与单元测试一起使用并以 100% 的覆盖率为目标将告诉您所有“测试”部分(假设它也全部成功)按照单元测试中的规定工作。
从技术设计/功能设计中编写单元测试,具有 100% 的覆盖率和 100% 成功的测试将告诉您程序的工作方式与文档中描述的一样。
现在你唯一需要的是好的文档,尤其是功能设计,程序员不应该写那些,除非他是那个特定领域的专家。
【讨论】:
100% 成功的单元测试实际上并不能告诉您程序是否像描述的那样工作。大多数单元测试都是在对象或功能级别完成的。每个都可以按需要工作,但它们的组合(未经单元测试)仍然可能是错误的。 请重新阅读,100% 覆盖率和 100% 单元测试会告诉您程序的工作方式与单元测试描述的一样 100% 覆盖率和 100% 单元测试仅意味着 100% 的代码在测试期间执行。测试是否能有效地测试行为完全是另一回事。【参考方案10】:在项目期间观察代码覆盖率趋势怎么样?
与许多其他指标一样,单个数字并不能说明太多。
例如,如果“我们的 Checkstyle 规则合规率为 78.765432%”,就很难判断是否存在问题。如果昨天的合规率是100%,我们肯定有麻烦了。如果昨天是 50%,我们可能做得很好。
当代码覆盖率随着时间的推移越来越低时,我总是会感到紧张。在某些情况下这是可以的,因此您在查看图表和数字时不能转头。
顺便说一句,声纳 (http://sonar.codehaus.org/) 是观察趋势的绝佳工具。
【讨论】:
【参考方案11】:SQLite 是一个extremely well-tested 库,您可以从中提取各种指标。
截至 3.6.14 版(报告中的所有统计数据均针对该版本的 SQLite),SQLite 库由大约 63.2 KSLOC 的 C 代码组成。 (KSLOC 的意思是数千个“源代码行”,或者换句话说,不包括空行和 cmets 的代码行。)相比之下,该项目的测试代码和测试脚本是 45261.5 KSLOC 的 715 倍。
最后,最让我印象深刻的是,这些可能的指标似乎没有一个比简单的陈述更重要,“它满足所有要求”。 (所以在实现的过程中不要忽视这个目标。)
如果你想判断团队的进步,那么你必须制定个人要求。这给了你一些东西可以指向并说“这个完成了,这个没有”。它不是线性的(解决每个需求都需要不同的工作),唯一可以线性化的方法是问题已经在其他地方解决(因此您可以量化每个需求的工作)。
【讨论】:
【参考方案12】:如果您正在寻找一些有用的指标来告诉您代码的质量(或缺乏质量),您应该查看以下指标:
-
圈复杂度
这是衡量方法复杂程度的指标。
通常 10 及以下为好,11-25 为差,更高为差。
嵌套深度
这是衡量一个方法中有多少嵌套范围的指标。
通常 4 及以下为好,5-8 为差,更高为差。
关系凝聚力
这是衡量包或程序集中的类型相关程度的指标。
关系凝聚力在某种程度上是一种相对指标,但仍然很有用。
可接受的水平取决于公式。鉴于以下情况:
R:包/程序集中的关系数
N:包/程序集中的类型数
H:类型之间关系的凝聚力
公式:H = (R+1)/N
根据上述公式,可接受的范围是 1.5 - 4.0
方法缺乏凝聚力 (LCOM)
这是衡量一个类的凝聚力的指标。
类的内聚度衡量每个方法引用的字段数量。
很好地表明您的班级是否符合单一职责原则。
公式:LCOM = 1 - (sum(MF)/M*F)
M:类中的方法数
F:类中的实例字段数
MF:类中访问特定实例字段的方法数
sum(MF):所有实例字段的MF之和
完全内聚的类的 LCOM 为 0。
完全非内聚的类的 LCOM 为 1。
您越接近 0,您的类就越有凝聚力和可维护性。
这些只是 NDepend(一个 .NET 指标和依赖映射实用程序)可以为您提供的一些关键指标。我最近在代码指标方面做了很多工作,这 4 个指标是我们发现最有用的核心关键指标。然而,NDepend 提供了其他几个有用的指标,包括传出和传入耦合以及抽象性和不稳定性,它们结合起来提供了一个很好的衡量标准,可以衡量您的代码的可维护性(以及您是否处于 NDepend 所称的痛苦区域或痛苦区域)没用。)
即使您不使用 .NET 平台,我也建议您查看NDepend metrics page。那里有很多有用的信息,您可以使用它们在您开发的任何平台上计算这些指标。
【讨论】:
+1 我在下班前给出了答案……我在回家的路上想到了 NDepend……它绝对是一个很棒的工具。【参考方案13】:(代码行数)/(测试用例数)怎么样?不是很有意义(因为它取决于 LOC),但至少它很容易计算。
另一个可能是(测试用例数)/(方法数)。
【讨论】:
(生产代码行)/(测试代码行)将是一个类似的度量。在使用 TDD 编写的项目中,测试代码的数量通常与生产代码大致相同(可能多或少 20%)。【参考方案14】:Crap4j 是我知道的一个相当不错的指标...
它是变更风险分析和预测软件度量的 Java 实现,它结合了自动化测试的圈复杂度和代码覆盖率。
【讨论】:
有趣的名字,但是非常好的工具。我试试看。【参考方案15】:错误指标也很重要:
出现的错误数量 已解决的错误数例如检测错误是否没有像新出现的那样快速解决。
【讨论】:
您可能会添加由于修复而引入的新错误 :) 正确的术语是有缺陷的,请参阅:***.com/questions/384423/bug-er-defect-terminology以上是关于代码覆盖率的替代指标是啥?的主要内容,如果未能解决你的问题,请参考以下文章
有啥方法可以从 Visual Studio 2017 中的 Catch C++ 测试中获取代码覆盖率指标?