unit-testing - 在进行单元测试时,100% 的代码覆盖率真的是一件好事吗?

标签 unit-testing documentation tdd code-maintainability

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

3年前关闭。




Improve this question




我总是了解到使用单元测试实现最大代码覆盖率是好的。我还听到微软等大公司的开发人员说,他们编写的测试代码行数比可执行代码本身多。

现在,真的很棒吗? 有时这看起来不是完全浪费时间,只会使维护变得更加困难吗?

例如,假设我有一个方法 DisplayBooks()它从数据库中填充书籍列表。产品要求说,如果店里有一百多本书,就只能展示一百本。

因此,使用 TDD,

  • 我将首先进行单元测试 BooksLimit()这将在数​​据库中保存两百本书,拨打 DisplayBooks() ,然后做一个 Assert.AreEqual(100, DisplayedBooks.Count) .
  • 然后我测试一下是否失败,
  • 那我换DisplayBooks()通过将结果的限制设置为 100 和
  • 最后我将重新运行测试,看看它是否成功。

  • 好吧,直接进入第三步是不是更容易,永远不要做BooksLimit()单元测试?当需求从 100 本书的限制变为 200 本书的限制时,只更改一个字符,而不是更改测试,运行测试以检查是否失败,更改代码并再次运行测试以检查是否成功,这不是更敏捷吗?

    注意:让我们假设代码是完整记录的。否则,有些人可能会说,他们是对的,做完整的单元测试将有助于理解缺乏文档的代码。事实上,有一个 BooksLimit()单元测试将非常清楚地显示要显示的最大数量的书籍,并且该最大数量为 100。单步进入非单元测试代码会困难得多,因为可以通过 for (int bookIndex = 0; bookIndex < 100; ... 实现这种限制。或 foreach ... if (count >= 100) break; .

    最佳答案

    Well, isn't it much more easier to go directly to the third step, and do never make BooksLimit() unit test at all?



    是的...如果您不花任何时间编写测试,那么编写测试的时间就会减少。您的项目总体上可能需要更长的时间,因为您将花费大量时间进行调试,但也许这更容易向您的经理解释?如果是这样的话……找一份新工作吧!测试对于提高您对软件的信心至关重要。

    当您拥有大量代码时,单元测试可提供最大值(value)。使用几个类很容易调试一个简单的家庭作业,而无需进行单元测试。一旦你走出去,你正在处理数百万行的代码库 - 你会需要它。您根本无法单步调试您的调试器。你根本无法理解一切。您需要知道您所依赖的类(class)是有效的。您需要知道是否有人说“我只是要对行为进行这种更改……因为我需要它”,但他们忘记了还有 200 种其他用途取决于该行为。单元测试有助于防止这种情况。

    关于使维护更加困难:不可能!我不能充分利用它。

    如果您是唯一参与过您的项目的人,那么是的,您可能会这么想。但那是疯狂的谈话!尝试在没有单元测试的情况下加快 30k 行项目的速度。尝试在没有单元测试的情况下添加需要对代码进行重大更改的功能。没有信心你没有打破其他工程师所做的隐含假设。对于维护者(或现有项目的新开发人员)来说,单元测试是关键。我依靠单元测试来记录文档、行为、假设,以及在我破坏某些东西(我认为不相关)时告诉我。有时,编写得不好的 API 的测试编写得也很差,而且更改起来可能是一场噩梦,因为这些测试占用了您所有的时间。最终你会想要重构这段代码并修复它,但你的用户也会感谢你——因为它,你的 API 将更容易使用。

    关于覆盖率的说明:

    对我来说,这不是 100% 的测试覆盖率。 100% 覆盖率并没有找到所有的错误,考虑一个有两个 if 的函数声明:
    // Will return a number less than or equal to 3
    int Bar(bool cond1, bool cond2) {
      int b;
      if (cond1) {
        b++;
      } else {
        b+=2;
      }
    
      if (cond2) {
        b+=2;
      } else {
        b++;
      }
    }
    

    现在考虑我编写一个测试来测试:
    EXPECT_EQ(3, Bar(true, true));
    EXPECT_EQ(3, Bar(false, false));
    

    那是 100% 的覆盖率。那也是不符合约定的函数-Bar(false, true);失败,因为它返回 4。所以“完全覆盖”不是最终目标。

    老实说,我会跳过 BooksLimit() 的测试.它返回一个常量,因此可能不值得花时间编写它们(并且应该在编写 DisplayBooks() 时对其进行测试)。当有人决定(错误地)根据货架尺寸计算该限制并且它不再满足我们的要求时,我可能会感到难过。我以前被“不值得测试”烧毁。去年我写了一些代码,我对我的同事说:“这个类主要是数据,不需要测试”。它有一个方法。它有一个错误。它进入生产阶段。它在半夜寻呼我们。我觉得很愚蠢。所以我写了测试。然后我仔细思考了哪些代码构成“不值得测试”。没有多少。

    所以,是的,你可以跳过一些测试。 100% 的测试覆盖率很棒,但这并不神奇地意味着您的软件是完美的。这一切都归结为面对变化时的信心。

    如果我把 class A , class Bclass C在一起,我发现一些不起作用的东西,我想花时间调试所有三个吗?不。我想知道AB已经满足了他们的契约(Contract)(通过单元测试)和我在 class C 中的新代码可能坏了。所以我对它进行了单元测试。如果我不进行单元测试,我怎么知道它坏了?通过单击一些按钮并尝试新代码?这很好,但还不够。一旦您的程序扩展,就不可能重新运行所有手动测试来检查一切是否正常。这就是为什么单元测试的人通常也会自动运行他们的测试。告诉我“通过”或“失败”,不要告诉我“输出是……”。

    好的,要去写一些更多的测试......

    关于unit-testing - 在进行单元测试时,100% 的代码覆盖率真的是一件好事吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3123777/

    相关文章:

    java - 如何在 Javadoc 中添加包级注释?

    actionscript-3 - 如何在 ActionScript 3.0 中使用 FlashVars?

    python - 在 Django 中,保存到数据库时如何返回现有模型实例

    tdd - 您如何确定哪种测试最能代表您要创建的功能?

    ios - 我的网络模拟功能应该包括什么?

    c# - 在测试中使用模拟

    python - 如何使用生产数据在 Django 中运行测试(只读)?

    c++ - Boost.Spirit 的单元测试

    c# - 如何 autodoc .Net Google 代码项目?

    c++ - GMock EXPECT_CALL 与 AnyMatcher 不匹配