代码之家  ›  专栏  ›  技术社区  ›  Fung

代码覆盖率陷阱[已关闭]

  •  30
  • Fung  · 技术社区  · 17 年前

    我最近在工作中注意到了这种情况,因为有一项政策要求实现100%的代码覆盖率。代码质量确实在提高,但相反地,测试人员似乎在编写更宽松的测试计划,因为“代码是完全经过单元测试的”。结果,一些逻辑错误成功地漏掉了。调试它们真的很痛苦,因为“代码是完全经过单元测试的”。

    我认为这部分是因为我们的工具只提供声明覆盖。不过,这本可以是更好的时间。

    如果任何人有代码覆盖政策的其他负面影响,请分享。我想知道现实世界中正在发生什么样的“问题”。

    编辑:谢谢你的回复。有几个答案我会记下来,但不幸的是,我只能记下一个。

    13 回复  |  直到 14 年前
        1
  •  59
  •   Mark Simpson    17 年前

    在一句话中:代码覆盖率告诉你你肯定要做什么 没有 有

    构建有价值的单元测试套件的一部分是找到最重要、高风险的代码,并对其提出难题。你要确保棘手的事情优先处理。覆盖率数字不知道代码的“重要性”,也不知道测试的质量。

    根据我的经验,您将编写的许多最重要的测试都是几乎没有添加任何覆盖率的测试(边缘案例在这里和那里添加了一些额外的百分比,但发现了大量的bug)。

    此外,人们开始沉迷于数字,而不是专注于测试的质量。我见过覆盖率为90%以上的写得很差的测试,就像我见过覆盖率只有60-70%的优秀测试一样。

    没有 已经过测试。

        2
  •  19
  •   Jason Cohen    17 年前

    仅仅因为存在代码覆盖率并不意味着您实际上正在测试通过函数的所有路径。

    例如,此代码有四条路径:

    if (A) { ... } else { ... }
    if (B) { ... } else { ... }
    

    然而,只有两个测试(例如,一个测试A和B为真,一个测试A和B为假)将给出“100%的代码覆盖率”

        3
  •  19
  •   Eric Melski    17 年前

    根据我的经验,代码覆盖率工具的最大问题是有人可能会成为“高代码覆盖率”等于“良好测试”的信念的受害者。大多数覆盖率工具只提供语句覆盖率指标,而不是条件、数据路径或决策覆盖率。这意味着有可能对以下代码进行100%覆盖:

    for (int i = 0; i < MAX_RETRIES; ++i) {
        if (someFunction() == MAGIC_NUMBER) {
            break;
        }
    }
    

    ... 从未在for循环上测试过终止条件。

    更糟糕的是,只调用应用程序的测试可能会获得非常高的“覆盖率”,而不必费心验证输出或错误地验证输出。

    简言之, 代码覆盖率级别当然表明测试不足,但是 覆盖率水平为 不

        4
  •  5
  •   Jason Cohen    17 年前

    有时,极端情况非常罕见,不值得测试,但严格的代码覆盖率规则要求您无论如何都要测试它。

    例如,在Java中,MD5算法是内置的,但从技术上讲,可能会引发“不支持的算法”类型的异常。它从未被抛出,您的测试必须经历重大的旋转才能测试该路径。

        5
  •  5
  •   Scotty Allen    17 年前

    在我看来,团队在衡量代码覆盖率时面临的最大危险是,它奖励大型测试,而惩罚小型测试。如果您可以选择编写一个覆盖应用程序大部分功能的单个测试,或者编写十个测试单个方法的小测试,那么仅测量代码覆盖率意味着您应该编写大型测试。

    然而,编写一组10个小测试将为您提供更少的脆弱性测试,并且将比一个大测试更彻底地测试您的应用程序。因此,通过测量代码覆盖率,特别是在一个测试习惯仍在发展的组织中,您常常会设置错误的激励。

        6
  •  3
  •   TofuBeer    17 年前

    任何测试,无论是哪种类型的测试,本身都是不够的。单元测试/代码覆盖面向开发人员。QA仍然需要对整个系统进行测试。业务用户还需要对整个系统进行测试。

    相反,QA完全测试代码,所以开发人员不应该测试同样糟糕的代码。测试是互补的,不同的测试提供不同的东西。每种测试类型都可能遗漏其他测试类型可能发现的内容。

        7
  •  2
  •   ojblass    17 年前
    1. 编写太有针对性的测试用例。
    2. 代码的输入可变性测试不足
    3. 不专注于因噪声导致的重要测试失败。
    4. 分配缺陷很困难,因为来自许多组件的许多条件必须相互作用才能执行一行。

    拥有100%覆盖率的目标最糟糕的副作用是花费大量的测试开发周期(75%+)来处理死角案例。这种政策的另一个不良影响是集中打击特定代码行,而不是处理输入范围。我真的不在乎strcpy函数是否至少运行过一次。我真的很关心它是否会遇到各种各样的输入。制定政策是好的。但任何极端严厉的政策都是不好的。代码覆盖率的100%指标既不必要,也不足以使代码被视为可靠的。

        8
  •  2
  •   Jörg W Mittag    17 年前

    什么 他们谈论的代码覆盖率类型。C0、C1、C2和更高级别代码覆盖率的特点如下: 非常

    n 决策点,你需要2个 N 测试(根据定义,值中的每一位都是一个决策点,因此要实现一个非常简单的函数的100%完整路径覆盖率,只需添加两个 int s、 您需要18446744073709551616测试)。如果你有 一 循环,你已经需要 测验。

    告诉你测试了什么代码。它只告诉你代码是什么 跑 ! 您可以自己尝试:使用一个代码覆盖率为100%的代码库。从测试中删除所有断言。现在是代码库 有100%的覆盖率,但不测试任何东西!因此,代码覆盖率不会告诉您测试了什么,只会告诉您未测试的内容。

        9
  •  2
  •   Mike    17 年前

    那里有工具, Jumble 首先,它通过分支覆盖率执行分析,通过改变代码来查看您的测试是否在所有不同的排列中失败。

    Jumble是类级别的变异 和朱尼特。突变的目的 测试用例的有效性。单人间 对代码执行变异,以 然后执行案件。如果 修改后的代码无法通过测试,然后 测验。相反,如果 代码通过了测试,这表明

        10
  •  1
  •   Otávio Décio    17 年前

        11
  •  1
  •   MrTelly    17 年前

    !00%的代码覆盖率意味着经过良好测试的代码完全是虚构的。作为开发人员,我们知道系统的硬/复杂/微妙部分,我更希望看到这些区域经过适当测试,只得到50%的覆盖率,而不是每一行至少运行一次的毫无意义的数字。

    在一个现实世界的例子中,我所在的唯一一个100%覆盖率的团队编写了一些我见过的最糟糕的代码。100%的覆盖率被用来代替代码审查——结果可以预见是糟糕的,以至于大多数代码都被扔掉了,即使它通过了测试。

        12
  •  1
  •   Bill Karwin    17 年前

    我们有很好的工具来测量单元测试的代码覆盖率。因此,很容易依赖100%的代码覆盖率来表示您“完成了测试”。这是不正确的。

    正如其他人提到的,100%的代码覆盖率并不能证明您已经进行了充分的测试,50%的代码覆盖率也不一定意味着您没有进行充分的测试。

    测量测试执行的代码行数只是一个指标。您还必须测试各种合理的函数输入,以及函数或类的行为如何取决于某些其他外部状态。例如,一些代码根据数据库或文件中的数据执行不同的功能。

    http://karwin.blogspot.com/2009/02/unit-test-coverage.html

        13
  •  1
  •   Julien    17 年前

    100%的代码覆盖率并不意味着你已经完成了usnit测试

    function int divide(int a, int b) {
        return a/b;
    }
    

    return divide(4,2) == 2;
    

    现在,没有人会争辩说这个100%覆盖率的单元代码表明他的特性工作得很好。