单元测试无用的项目类型

时间:2009-02-06 15:54:40

标签: unit-testing tdd

您是否认为单元测试(以及测试驱动开发)必须在任何情况下完成,或者是否存在一些例外情况。 我最近一直致力于项目的类型,我无法看到单元测试如何有用或改进设计,代码质量等。一种类型的项目是PDF报告生成器,它采用聚合数据(已计算的值和QAed)并将其输出到PDF报告文件。另一种类型是使用第三方ORM工具的直接CRUD应用程序。 我可以看到有人可以为使用CRUD应用程序的单元测试做出争论,但这是一个不必要的和耗时的设置工作,比如捅掉所有对数据库的调用和模拟业务对象等等。你需要知道数据库是否发生了什么事。 那么当人们应该使用或避免单元测试时呢?

由于

17 个答案:

答案 0 :(得分:14)

请不要将单元测试(UT)(一种工具)与测试驱动设计(TDD)混淆,后者是一种方法论。 see this for more

另外,请记住,单元测试的好处之一是用于回归测试,即针对未来重大变更的保险(并帮助验证修复的错误不会变得不固定)。

在您的第一个示例中,我将按如下方式对PDF转换进行单元测试:

  • 从一组已知的样本数据开始,并生成PDF文档
  • 手动验证生成的PDF是否正确
  • 保留示例数据并将PDF文档更正为测试套件的一部分
  • 编写一个函数来比较两个PDF文档的差异(在二进制或内容级别,视情况而定)
  • 自动执行此单元测试,将从样本数据生成的PDF文档与第一步中经过验证的文档进行比较

现在,每当您更改PDF生成代码时,您都会进行自动单元测试,以验证您是否至少文件生成 以获取样本数据和输出格式。

我使用相同的技术来验证HTML呈现的页面,GUI屏幕等。手动验证基线,然后自动进行比较。这为未来的重大变革提供了保险。

当然,如果您的输出格式经常更改,这可能没那么有用,但基本输出格式的基线测试可能会有很长的使用寿命。

在你的第二个例子中,听起来你会测试第三方ORM工具,这可能毫无意义。但是,根据您使用该工具的方式,一些基线测试可能有助于防范未来的重大变更。例如,不是模拟整个n层链(我不是在没有必要时嘲笑的粉丝),只需使用ORM工具来创建,读取,更新和删除典型的对象/记录,使用(测试)数据库上的直接SQL语句验证操作。这样,如果第三方供应商稍后更新了破坏您将了解的基本功能的内容,并且项目的新开发人员可以轻松地了解如何使用单元测试示例中的ORM工具。

答案 1 :(得分:11)

它通常主要取决于计划约束以及您将如何处理代码。如果你正在写一次性(很多人认为不存在),我认为不需要进行单元测试。

但是,如果您正在编写将来可能会重复使用或重新考虑的模块化软件 - 单元测试非常有用。

我经常发现它们的主要目的不是确定当前实现中的错误,而是确保在更改到来时不会引入错误。

答案 2 :(得分:9)

我从来没有真正遇到过单元测试应用程序视图层的策略。

但是,我希望有人能证明我的错误。

答案 3 :(得分:9)

解释Jeff& Joel最近对SOB的评论:当你为产品增加价值时,你应该进行单元测试。

在您描述的两种情况下,您将能够以与编写单元测试相同的成本进行全面的临时修复(和/或事后回归测试)。所以不要编写单元测试。

答案 4 :(得分:5)

“......这是一个不必要且耗时的设置工作,比如刺破所有对数据库的调用和模拟业务对象等等,最后你需要知道数据库是否发生了什么。 “

听起来你正在测试错误的东西。

为什么要删除数据库调用?为什么不创建一个测试数据库并测试针对该测试数据库的实际数据库调用? [这就是Django测试服务器的工作方式,它很棒。]

为什么要模拟业务对象?这就是你正在测试的,对吗?可以说“我们假设ORM正常工作”并声明您的“单位”是业务对象+ ORM +数据库。测试一下,因为问题就出现了。

单元测试你写的东西。

您下载的内容应该有自己的单元测试。

单元测试可以分层次 - 您可以编写类似集成的测试,假设ORM层已经通过了所有测试。

答案 5 :(得分:4)

我认为你应该避免对代码不需要工作的项目进行单元测试。

如果您希望代码现在正常工作,并且希望将来在有修改时继续工作,则单元测试非常有用。在这样的项目上,它不仅可以节省时间,而且还可以节省所有其他费用。

答案 6 :(得分:3)

“我曾经听过有人说,如果他在没有测试的情况下编写超过10行代码,那么他就会开始不确定他刚写的代码是否能正常工作。”

这个人对自己是一种危险。立即从代码中删除它们。

答案 7 :(得分:2)

我同意瑞恩的观点。唯一有用的单元测试形式是测试一些算法行为的测试,这通常只是程序的一小部分。

如果你发现自己正在编写有用的单元测试,那么你的工作可能不常见:)

编辑:相反,集成测试通常非常有用,但是自动化单元测试要困难得多。

答案 8 :(得分:2)

我想说,只要你在项目中创建了第一个函数,就需要对它进行单元测试。如果您的代码库完全由副作用代码组成,例如shell脚本,那么您可以执行其他类型的自动化测试,但如果不是像Esko Luontola所描述的一些一次性代码,您最好编写任何自动化测试而不是最终无。

但是,在完整应用程序的某些区域,没有自动化工具可以为您进行检查。 GUI和屏幕上呈现的所有内容都是一个例子,因为即使是Selenium也没有自动检查出现动画的模态窗口是否确实播放并且不是故障的界面。你必须使用真实的人来手动测试这些东西,这是正确的QA的现实。

您的PDF示例存在缺陷,因为您不想在PDF生成器中测试哪些功能集。如果您需要确保已生成的PDF中已经检查过的数据存在,您甚至可以通过搜索该数据的文件执行grep,例如grep,因为PDF只不过是一个包含二进制blob的文本文件,在这种情况下可以安全地跳过它。如果您需要确保格式是正确的,那么目前无法自动化它,因此您需要手动测试它。

在CRUD示例中,您不存根第三方ORM工具。你在它周围写了一个包装器,因为在接下来的两年里,ORM工具要么被更闪亮的东西所取代,要么只是接收一些BC不兼容的更新。然后,您专门为此包装器编写fullstack集成测试,以确保它完成您的应用程序所需的操作,然后在所有其他测试中模拟包装器以防止它们依赖于运行时环境。这两种类型的测试对于防止回归和支持重构都至关重要。

总之,我应该注意,如果您完全关心最终的应用程序,您将测试功能的有效性。重点是,每次手动测试应用程序都是一场噩梦,导致几乎没有任何测试。所以你需要自动化测试。为了获得最佳反馈,您希望这些自动化测试尽可能经常运行,理想情况是不断进行。对于它,你需要他们快速疯狂。对于自动化测试用例来说,快速疯狂,没有比只测试与此案例相关的东西更好的解决方案。因此,我们以单元测试定义结束,并自然地做到了。

答案 9 :(得分:2)

要回答你的问题,肯定有一些例外。

事实上,我认为自动化白盒测试的有用性更可能是例外而不是规则。

需要额外的时间,必须在有重大变化,减速和阻碍开发的任何时候重写测试。此外,只是因为您的测试通过并不保证您的应用程序正常工作或解决了用户的问题。

使用自动化测试进行白盒测试已经成为工具箱中的一个工具了一段时间 - 最近由于某种原因它风靡一时,如果你反对它,你会被TDD狂热者排斥到某种程度。

更好地理解它,并在它可能有用的地方使用它。例如,我的一个朋友是Microsoft Frarmework团队的SDET - 这是TDD是一项重要资产的gerat示例。也就是说,他们正在为数百万人使用的开发环境开发引擎。

对于您的磨坊网络应用程序,甚至是企业级别的运行,我怀疑这种严谨性是值得增加的时间和复杂性。但是,如果你有一个将被广泛使用/重新起诉的关键组件,那么这些组件可能是值得的。

答案 10 :(得分:1)

  • 例如,为用户界面/表示层编写自动化测试通常不值得。在这种情况下,通常最好保持表示层非常薄,并且具有包含表示层的所有功能的可测试层。然后表示层将主要是声明性的,并且只包含简单的胶水代码。当一切都是声明性的,几乎没有什么可以破解,所以测试它是没有必要的。诸如UI元素正确对齐的事情,布局正确,标签是否正确等等更容易手动测试。

  • 丢失代码。如果代码只使用一次,并且它的工作正常并不重要,并且如果需要修改代码,则可以重写它,编写高质量的代码和测试可能没有好处。但是当代码变大或需要维护代码时,或者代码工作正常非常重要时,编写测试值得付出努力。我曾经听过有人说,如果他在没有测试的情况下编写超过10行代码,那么他就会开始不确定他刚写的代码是否正常。

答案 11 :(得分:0)

当编码过程符合所有精益生产原则时,单元测试变得毫无用处。那就是:

  • 功能是最短的(及时)

  • 您在完成后手动测试,最具特色的情况(海贼王流)

  • 当程序崩溃时,它会告诉您确切的位置和原因。哪个函数调用哪个,错误信息清晰(Jidoka)

  • 编程语言只能通过显式代码使程序崩溃,就像Go编程语言一样(Poka-Yoke)

Path to Jidoka

答案 12 :(得分:0)

单元测试可能是质量保证流程的一部分,但不应该是整个质量保证流程。

通常,单元测试用作:

a)某些质量检查使用单元测试,这些过程通常会错过许多无法自动测试的麻烦。例如(并没有那么奇怪),懒惰的QA人要求进行现成的单元测试,然后他们可以输入一些值并称之为一天。

b)其他QA用作其他测试的补充。但是,我的趋势(总是?)是多余的。

因此,除非单元测试无痛(特别是不添加或修改代码),否则老派测试就是解决方案(在任何情况下都应该进行手动测试)。

答案 13 :(得分:0)

如果您的代码将由其他人审核或使用,则应对其进行测试。如果不是在班级,那么在更高的水平。我讨厌当人们发现他们的代码进行审核时很明显他们没有花时间去讨论它的工作原理(或者更糟糕的是甚至没有编译)。

我很少找到任何价值的单元测试(在课堂级别)。在开发代码时,我可以通过遍历调试器轻松地进行这种测试。我更喜欢测试应该作为一个单元一起工作的类。采取这种方法,我更加努力。毕竟,我真的不在乎functionX是否完全符合我认为它本身应该做的事情,但是当它与系统中的其他类一起工作时,它并没有做它需要做的事情。

答案 14 :(得分:0)

我正在研究与生产机器接口的软件(使用某种行业标准作为通信协议)。 因此,通信器类的大多数方法都是由来自机器的消息触发的,它们永远不会从外部调用。所以我把它们变成了私人。

如果我想测试这个功能,我需要创建一个模拟机器行为的模拟器,以便在这个类上运行一些黑盒子测试。构建模拟器可能至少占通信器所需时间的50%。

我本可以将机器触发的功能公之于众,但这在我们的团队中引发了一些非常激烈的争论......

答案 15 :(得分:0)

如果测试返回的值小于开发和执行单元测试的成本,则避免单元测试。这通常归结为风险分析和一段代码的预期寿命。

答案 16 :(得分:0)

我永远不会说,仅仅是因为人们可能已经倾向于执行比必要更少的单元测试。如果我们说“可能没有必要进行单元测试”那么我们就会为各种借口敞开大门......