我看到很多问题问如何在特定语言中进行单元测试,但没有问题问“什么”,“为什么”和“何时”。
- 它是什么?
- 它对我有什么作用?
- 为什么我应该使用它?
- 什么时候应该使用它(也包括什么时候不需要)?
- 有哪些常见的陷阱和误解?
我看到很多问题问如何在特定语言中进行单元测试,但没有问题问“什么”,“为什么”和“何时”。
单元测试大致上是使用测试代码对你的代码片段进行隔离测试。它所带来的直接好处包括:
请注意,如果你的测试代码写入文件、打开数据库连接或执行网络操作,则更适合将其归类为集成测试。集成测试也很重要,但不应将其与单元测试混淆。单元测试代码应该简短、简洁且执行速度快。
另一种理解单元测试的方法是,先编写测试。这被称为测试驱动开发(TDD)。TDD 带来了额外的优势:
如果你现在还没有进行单元测试,我建议你开始尝试。找一本好书,任何一本 xUnit 书籍都可以,因为它们之间的概念非常可转移。
有时编写单元测试会很痛苦。当这种情况发生时,尝试寻找帮助,并抵制“只编写该死的代码”的诱惑。单元测试很像洗碗。它并不总是愉快的,但它可以保持你比喻中的厨房清洁,而你真的希望它是干净的。 :)
编辑:我想到了一个误解,尽管我不确定它是否很普遍。我听过一个项目经理说,单元测试让团队把所有的代码都重写了一遍。如果看起来和感觉不对,那么你做错了。编写测试通常不仅可以加快开发速度,而且还可以为你提供方便的“现在我完成了”指示器,否则你将无法获得这个指示器。
我不反对Dan的说法(虽然更好的选择可能是不回答)......但是......
单元测试是编写代码来测试系统行为和功能的过程。
显然,测试可以提高您的代码质量,但这只是单元测试的表面好处。真正的好处在于:
您应该进行单元测试,因为提供维护性和质量产品给客户符合您的利益。
我建议在任何模拟现实世界行为的系统或系统的一部分中使用它。换句话说,它特别适用于企业开发。我不会将其用于一次性/实用程序。我也不会将其用于难以测试的系统部分(UI是常见的例子,但并非总是如此)
最大的陷阱是开发人员测试的单元过大,或将方法视为单元。如果您不理解控制反转,这一点尤其正确 – 在这种情况下,您的单元测试将始终变成端到端的集成测试。单元测试应该测试个别行为 - 大多数方法具有许多行为。
最大的误解是程序员不应该进行测试。只有糟糕或懒惰的程序员才持这种观点。修建你屋顶的工人不应该测试吗?更换心脏瓣膜的医生不应该测试新瓣膜吗?只有程序员能够测试他的代码是否按照他的意图执行(QA可以测试边缘情况-当代码被告知执行程序员不想要的操作时,代码如何行为,客户可以进行验收测试-代码是否完成了客户支付的任务)。
单元测试与“只需打开一个新项目并测试特定代码”相比的主要区别在于它是自动化的,因此可重复。
如果您手动测试代码,它可能会让您相信代码在其当前状态下完美地工作。但是,当您一周后对其进行了微小修改时呢?您愿意每次代码中的任何更改时都手动重新测试吗?很可能不会 :-(
但是,如果您可以随时以几秒钟的时间内单击运行测试,并且以完全相同的方式执行测试,那么它们将立即向您显示什么已经出现问题。如果您还将单元测试集成到自动构建过程中,则它们甚至会在看似完全无关的更改导致代码库中某个遥远部分出现问题时警告您-这时,您甚至不会想到需要重新测试该特定功能。
这是单元测试胜过手动测试的主要优势。 但是等等,还有更多:
相应的,单元测试框架使您可以轻松编写和运行测试。
我在大学里从未学过单元测试,花了一段时间才“懂”它。我读了一些介绍,想到了“啊,对了,自动化测试,可能很棒”,然后就把它忘了。
在我真正理解单元测试的意义之前,又过了相当长的一段时间: 假设你正在开发一个大型系统并编写一个小模块。它编译通过了,你测试了一下,结果很好,然后你就转向下一个任务。九个月后,两个版本后,有人对程序中某个看似无关的部分进行了更改,但这破坏了该模块。更糟的是,他们测试了自己的更改,他们的代码工作正常,但他们没有测试你的模块; 甚至他们可能不知道你的模块存在。
现在你有一个问题:有错误的代码在主干分支上,而且没有人知道。最好的情况是内部测试人员在你发货之前找到它,但在游戏的最后时刻修复代码是昂贵的。如果没有内部测试人员发现它......嗯,那可能会变得非常昂贵。
解决方案就是单元测试。它们将在编写代码时捕获问题——这很好——但你可以手动完成。真正的回报是,当你现在正在处理完全不同的项目时,一名暑期实习生认为如果那些参数按字母顺序排列会更整洁——然后你之前编写的单元测试失败了,有人用东西扔向实习生,直到他把参数顺序改回去。这就是单元测试的“为什么”。 :-)
在探索TDD的道路上,对于单元测试和TDD的哲学优点,以下是我初步的、关键"启发式"观察(并不原创或一定是新闻)...
TDD不意味着编写两倍的代码。测试代码通常编写起来相当快速和轻松,并且是设计过程的关键部分和至关重要。
TDD帮助您意识到何时停止编码!您的测试让您有信心,认为您已经足够了,可以停止调整并继续进行下一步操作。
测试和代码共同努力实现更好的代码。您的代码可能很糟糕/有错误。您的测试也可能很糟糕/有错误。在TDD中,您指望两者都很糟糕/有错误的可能性相当低。通常是测试需要修复,但这仍然是一个好结果。
TDD有助于解决编码便秘的问题。您知道有那种感觉,有很多事情要做,你几乎不知道从哪里开始?现在是周五下午,如果你再拖延几个小时...TDD允许您快速地实现您认为需要做的事情,并快速启动您的编码。而且,就像实验室老鼠一样,我认为我们都会响应那个大绿灯,并努力再次看到它!
同样地,这些设计师类型可以看到他们正在处理的内容。他们可以走开喝果汁/抽烟/玩iphone,然后回到一个立即给他们一个视觉提示的监视器。TDD给了我们类似的东西。当生活干预时,更容易看出我们到了哪里...
我想是福勒说过:"不完美的测试,经常运行,要比完美的测试根本没有写好得多"。我理解这意味着允许我在我认为它们最有用的地方编写测试,即使我的代码覆盖率非常不完整。
TDD在各种意想不到的方面有所帮助。良好的单元测试可以帮助记录某个功能应该如何运行,它们可以帮助您将代码从一个项目迁移到另一个项目,并让您对未进行测试的同事产生了一种无端的优越感 :)
这个演示文稿是介绍所有与测试相关内容的最佳入门材料。
我使用单元测试来节省时间。
在构建业务逻辑(或数据访问)时,测试功能通常涉及将内容输入到许多可能尚未完成的屏幕中。自动化这些测试可以节省时间。
对我而言,单元测试是一种模块化测试工具。通常每个公共函数都至少有一个测试。我编写其他测试以覆盖各种行为。
您在开发代码时想到的所有特殊情况都可以记录在单元测试的代码中。单元测试也成为使用代码的示例来源。
对于我来说,通过单元测试发现我的新代码破坏了什么比提交代码并由前端开发人员发现问题要快得多。
对于数据访问测试,我尝试编写没有更改或清理自己的测试。
单元测试无法解决所有测试需求。它们将能够节省开发时间并测试应用程序的核心部分。
单元测试是编写测试应用程序代码的代码。
名称中的“单元”部分指的是一次测试小代码单元(例如一个方法)的意图。
xUnit可帮助进行此测试-它们是协助进行此操作的框架。其中一部分是自动化测试运行器,告诉您哪些测试失败,哪些测试通过。
它们还具有在每个测试之前设置需要的公共代码并在所有测试完成后进行拆除的功能。
您可以进行测试以检查是否已引发了预期的异常,而无需自己编写整个try catch块。