没有编写单元测试的任何好的论据?

时间:2010-05-29 01:26:51

标签: unit-testing

我已经阅读了很多关于单元测试的乐趣和令人敬畏的观点。对单元测试有充分的理由吗?

22 个答案:

答案 0 :(得分:55)

在我以前工作的地方,单元测试通常被用作与较小的测试部门一起运行的理由;逻辑是“我们有UNIT TESTS !!我们的代码不可能失败!因为我们有单元测试,我们不需要真正的测试人员!”

当然,这种逻辑是有缺陷的。我见过很多你不相信测试的情况。我也看到很多情况,由于时间紧迫,测试变得过时 - 当你有一个星期做大工作时,大多数开发人员会花一周的时间来做真正的代码并运送产品,而不是重构单元测试第一周,然后再请求至少一周做真实的代码,然后花费最后一周使单元测试与他们实际编写的内容保持同步。

我还看到过单元测试中涉及的业务逻辑比隐藏在应用程序中的逻辑更加可怕和难以理解的情况。当这些测试失败时,您需要花费两倍的时间来解决问题 - 测试存在缺陷,还是真正的代码?

现在狂热者不会喜欢这一点:我工作的地方很大程度上是使用单元测试逃脱的,因为开发人员的口径足够高,很难证明编写单元测试的时间和资源是合理的(不是提到我们使用REAL测试人员)。真的。写单元测试只会给我们带来最小的价值,投资回报就不存在了。当然它会给人一种温暖的模糊感觉 - “我可以在晚上睡觉,因为我的代码是通过单元测试保护的,因此宇宙处于一个很好的平衡状态”,但实际情况是我们在编写软件的业务,不给管理者带来温暖的模糊感受。

当然,进行单元测试绝对有充分的理由。单元测试和TDD的问题是:

  • 有太多人打赌家庭农场。
  • 太多人将其用作宗教,而不仅仅是一种工具或其他方法。
  • 太多人试图从中赚钱,这已经扭曲了应该如何使用

实际上,它应该被用作日常使用的工具或方法的一个,并且它永远不应该成为 单一方法。

答案 1 :(得分:27)

重要的是要明白它不是免费的。测试需要努力编写 - 更重要的是,维护。

项目经理和开发团队需要了解这一点。

答案 2 :(得分:26)

实际上我的错误都不会通过单元测试找到。我的错误主要是集成或意外用例错误,为了更早发现它们,更广泛(并且理想情况下是自动化的)系统测试将是最好的选择。

正如dummymo所说,我正在等待更多以证据为基础,而不是以宗教为基础的单位测试论据。我并不是指某些学术环境中的某些实验;我的意思是,对于我的开发场景和编程能力,成本效益将是积极的。

所以,同意OP的其他答案:因为他们花费时间和成本效益没有显示。

答案 3 :(得分:15)

您的数据访问层不容易适应模拟。

答案 4 :(得分:10)

简单的事实是,当你编写一些代码时,你必须确保它在你说它完成之前有效。这意味着你运用它 - 构建一些脚手架来调用函数,传递一些参数,检查以确保它返回你期望的。是否有额外的工作,保持脚手架,所以你可以再次运行测试?

是的,实际上,它可以。通常情况下,即使代码正确,测试也会失败,因为您使用的数据不再一致,等等。

但是如果你有一个单元测试框架,那么保持测试代码的成本只会比扔掉它的成本略高。虽然是,您会发现许多测试用例都会因为您使用的数据出现问题而失败,而不是代码问题,当您学习如何构建测试以便最大限度地减少测试时问题

是的,通过单元测试并不能保证您的系统正常运行。但它确实提供了某些子系统正在工作的保证,这不是什么。测试用例提供了如何调用函数的有用示例。

这不是灵丹妙药,但这是一种有用的做法。

答案 5 :(得分:9)

正式验证。

如果你可以正式证明代码的正确性,除非测试条件带来新的变量,否则没有理由进行单元测试,在这种情况下,你仍然只进行少量的单元测试(或证明新变量)。

答案 6 :(得分:8)

单元测试将告诉您一个特定的类方法是否正确设置变量(或者某个变量)。无论如何,形状或形式都不表示您的应用程序将正常运行,或者它将处理它需要处理的环境。

您可以考虑编写测试的任何问题,您将在代码中处理,并且该问题永远不会出现。那么你就有300个测试通过,但是你想要测试的真实场景。因此,创建和维护测试所需的工作不一定值得。

答案 7 :(得分:5)

非确定性结果。

在简单的情况下,您可以为随机生成器播种(或以某种方式模拟它们)以获得可重现的结果,但是当算法很复杂时,这变得不可能,因为代码更改将改变对随机数的需求,从而改变结果。

这在商业环境中很少遇到,但在游戏中很有可能。

答案 8 :(得分:5)

这是通常的成本/收益分析。

成本:您需要花时间开发和维护测试,并将资源用于实际运行。

众所周知的好处(大多数便宜的维护/重构和更少的错误)。

所以,你在项目的背景下平衡一个。

如果它是一个一次性的快速黑客,你知道永远不会被重复使用,单元测试可能没有意义。虽然说实话,如果我看到每次一次性快速黑客的一美元,我看到多年后或更糟,多年后不得不维护/重构,我可能会成为投资SO的风险资本家之一:)< / p>

答案 9 :(得分:3)

懒惰;有时候我很懒,只是不想这样做!

但严重的是,单元测试很棒,但如果我只是编写自己的乐趣,我通常不会这样做,因为项目是短暂的,我是唯一一个正在进行测试的人,他们'不是那么大。

答案 10 :(得分:3)

无法概括单元测试将提供成本效益的地方以及不提供成本效益的地方。我看到很多人强烈反对单元测试并指责那些不使用TDD的人,而完全忽略了应用程序可能与现实世界不同的事实。

例如,当你有很多集成点时,无论是在系统之间,还是在你自己的应用程序的进程和线程之间,都很难从单元测试中获得任何有用的东西。

如果您所做的一切都是像Stackoverflow这样的网站,其中问题域很容易理解,而且大多数解决方案都相当简单,那么是的,编写单元测试有很多好处,但是有很多应用程序可以简单地使用没有正确的单元测试,因为他们缺乏,“单位”。

答案 11 :(得分:3)

  • 测试就像保险。
    • 你没有把所有的钱都投入其中。
    • 但你不能避免你的人寿保险。 (美国人应该仍然记得健康保险法案。)
    • 保险是邪恶的。
    • 但是但是......
      • 您没有得到投保,期待致命事故能够收回您投入保险计划的所有款项。

总之,

  • 有一些理由来编写测试。
  • 单元测试有时是前进的众多方法之一
  • 但是 没有理由只关注写作(单元)测试。

答案 12 :(得分:3)

  • 它可以阻止尝试多种变体,尤其是在项目的早期阶段。 (但它也可以鼓励在后期进行试验!)

  • 它不能取代系统测试,因为它不包括组件之间的关系。因此,如果您必须在系统测试和单元测试之间分配可用的测试时间,那么过多的单元测试会对系统测试的数量产生负面影响。

我想补充一点,我通常鼓励进行单元测试!

答案 13 :(得分:2)

永远不会有理由不编写单元测试。

有充分的理由不编写特定的单元测试。 (特别是如果你使用代码生成。当然你可以编写代码生成单元测试,以确保没有人使用生成的代码。但这取决于信任团队。)

*编辑

喔。根据我的理解,函数式编程中的一些东西要么编译就可以工作,要么不编译。

那些东西需要单元测试吗?

答案 14 :(得分:2)

我不会说这是反对它的论据,但对我们来说,我们有一个带有TON代码的遗留应用程序,并用COBOL编写。现在几乎不可能说我们想要实施单元测试,并且在duffymo指出的任何程度的准确性或合理的业务时间范围内进行测试。

所以我想补充一点,也许一个论点是在开发完成(并且维护多年)后尝试实施单元测试的无能(在某些情况下)。

答案 15 :(得分:2)

我同意这样的观点:对于单元测试一般没有好的论据。然而,在某些特定情况下,单元测试可能不是一个可行的选择,或者至少是有问题的,并且/或者对于创建和维护测试所涉及的工作量水平而言是一个困难的投资回报主张。

以下是一些例子:

  • 响应外部条件的实时依赖行为。一些纯粹主义者可能认为这不是单元测试,而是涉及集成或系统测试级别的场景。但是,我为准嵌入式应用程序编写了简单的低级功能代码,通过单元测试框架至少部分地测试实时响应,以进行构建/回归测试。

  • 测试行为和/或策略级功能,这些功能需要测试代码模块响应的环境状态的复杂数据描述。这与earlier poster's comment有关,涉及难以进行涉及数据访问层的单元测试,该数据访问层不易于模拟。虽然正在测试的行为/策略可能相对简单,但需要在复杂的状态描述中进行测试。这里进行单元测试的价值在于确保为任务关键型应用程序正确处理罕见但关键的条件。一个人想模仿后者并创建一个模拟的环境/状态,但这样做的成本可能很高。

上述情景的单元测试至少有两种替代方案:

  • 对于实时或准实时功能测试,可以进行广泛的系统测试,以弥补缺乏良好的单元测试。对于某些应用,这可能是唯一的选择,例如涉及硬件和/或物理系统的嵌入式系统。

  • 创建测试工具或系统级模拟器,以便在一系列随机模拟条件下进行广泛测试。这对于测试前面涉及复杂环境状态的策略/行为场景非常有用。尽管在创建测试工具或模拟器方面可能涉及大量工作,但投资回报可能比隔离单元测试的价值要好得多,因为可以测试更广泛的条件。

    由于测试环境涉及随机而非特定条件,因此这种方法可能无法为某些关键任务场景提供所需的保证级别。进行广泛的测试可能有助于弥补这一点。或者,为随机条件创建测试工具或系统模拟器也可以帮助降低测试特定复杂状态方案的总体成本,因为开发成本现在可以在更广泛的测试需求中共享。

最后,如何最好地测试任何给定的应用程序,取决于成本与价值。单元测试是最佳选择之一,应尽可能在可行的情况下使用,但并非普遍适用于所有情况。像软件中的许多东西一样,有时它只是一个必须做出的判断调用,然后准备根据结果进行调整。

答案 16 :(得分:2)

单元测试是一种权衡。我看到两个问题:

  • 需要时间。如果你想做一个重要的改变,不仅要编写测试,而且(这也是最烦人的),现在你需要修改两个地方。在最糟糕的情况下,它可能会阻止您重新构建代码库。

  • 它只能防止认为可能出现的问题,并且您大多无法测试副作用。如前所述,这可能导致错误的安全感。

我同意单元测试是一种有价值的工具,可以通过相对稳定的代码库来提高企业软件的可靠性。但对于个人项目或婴儿项目,我认为在代码中大量使用断言是一个更好的权衡。

答案 17 :(得分:1)

我们不是完全摆脱它们,而是仅针对核心功能(如支付授权,用户身份验证等)编写单元测试。它非常有用,因为总会有一些触摸点对代码更改非常敏感。一个庞大的代码库,您可能需要一些方法来验证这些接触点的工作,而不会在QA中失败。

答案 18 :(得分:1)

对于一般的单元测试,学习曲线是我所知道的最重要的原因。我一直在努力学习良好的单元测试约1。5年,我觉得我只是擅长它(编写审计日志间谍,嘲笑,测试每个测试1个约束等),虽然我觉得它有为我增加了开发时间约1年。所以在它开始付清之前称之为6个月的奋斗。 (当然,那段时间我还在做“真正的”工作。)

在此期间经历的大部分疼痛是由于未遵循良好单位测试的指导原则。

对于各种特定情况,可能会阻止单元测试的能力;其他人对其中的一些进行了评论。

答案 19 :(得分:0)

在测试驱动开发中,单元测试实际上更重要的是设计代码可以开始测试的方法。事实证明,您的代码往往更加模块化,编写测试有助于充实API等等。

很多时候,你会发现自己正在开发代码然后编写测试,注释掉你刚写的代码以确保测试失败,然后有选择地删除注释标记以使测试通过。为什么?好吧,因为编写测试比在某些情况下编写代码要困难得多。编写可以完全自动化方式测试的代码通常要困难得多。考虑用户界面,生成图像或pdf的代码,数据库事务。

因此,单元测试确实有很多帮助,但是期望为测试编写的代码大约是实际代码的3倍。此外,所有这些都需要保持。对应用程序的重大更改将使大量测试无效 - 这是对系统影响的一个很好的衡量标准,但仍然......你准备好了吗?你是一个小团队,你在做5个开发人员的工作吗?如果是这样,那么自动TDD开发就不会飞 - 你没有时间足够快地完成任务。那么你最终依靠你自己的手动测试,QA测试的东西,只是生活在错误的滑动​​,然后尽快修复。这是不幸的,高压和恼怒,但在没有雇用足够的开发人员来完成需要完成的工作的小公司中,这是现实。

答案 20 :(得分:0)

不,我真的没有。根据我的经验,那些做过的人正在提出一个稻草人的论点,或者只是不知道如何对不明显如何进行单元测试的事情进行单元测试。

@Khorkak - 如果您更改了生产代码中的某项功能,则只会对您的一系列单元测试产生影响。如果不这样做意味着您没有将生产代码与测试隔离开来,而是在集成中排除大量生产代码。这只是糟糕的单元测试技能,是的,这是一个很大的问题。不仅因为你的单元测试代码库难以维护,还因为你的生产代码库会很糟糕并且遇到同样的问题。

答案 21 :(得分:0)

单元测试对于一次性代码没有任何意义:如果代码是Q&amp; D概念证明,那么在尖峰期间创建的用于调查各种方法的东西,或者您确定的任何其他内容几乎总是被抛弃,然后执行单元测试不会给投资带来太多回报。事实上,他们可能会伤害你,因为在那里度过的时间花费的时间不是尝试不同的方法等(替代成本)

关键是确保是这种情况,或者对队友等有足够的理解,如果有人说'那很好,那就用那个'然后投入时间将代码提升到NON一次性代码的标准。

对于那些要求更好证明的人,我会推荐你​​到这个页面。 http://biblio.gdinwiddie.com/biblio/StudiesOfTestDrivenDevelopment 请注意,其中许多都是按学术类型进行的研究,但针对进行真正的生产软件工作的小组进行了研究,所以个人认为它们的有效性非常高。