什么是单元测试?
我看到许多问题询问"如何"以特定语言进行单元测试,但没有问题询问"什么","为什么"和"何时"。
- 它是什么?
- 它对我有什么作用?
- 我为什么要使用它?
- 我什么时候应该使用它?
- 有哪些常见的陷阱和误解
解决方案
回答
粗略地说,单元测试是与测试代码隔离地测试代码的各个部分。我想到的直接好处是:
- 运行测试变得自动化且可重复
- 与通过GUI进行点击测试相比,我们可以进行更精细的测试
请注意,如果测试代码写入文件,打开数据库连接或者通过网络执行某些操作,则将其更恰当地归类为集成测试。集成测试是一件好事,但不要与单元测试相混淆。单元测试代码应该简短,甜美并且可以快速执行。
查看单元测试的另一种方法是先编写测试。这就是所谓的测试驱动开发(TDD)。 TDD具有其他优势:
- 我们无需编写推测性的"将来可能会需要"代码,仅足以使测试通过
- 我们编写的代码始终包含在测试中
- 通过首先编写测试,我们被迫考虑如何调用代码,从长远来看,这通常可以改善代码的设计。
如果我们现在不进行单元测试,建议我们开始使用它。获得一本好书,几乎任何xUnit-book都可以做,因为这些概念之间可以很容易地转移。
有时编写单元测试会很痛苦。当这种方式得到解决时,请尝试寻找可以帮助人,并抵制"只写该死的代码"的诱惑。单元测试很像洗碗。它并不总是那么令人愉快,但是它可以使隐喻厨房保持清洁,并且我们真的希望它保持清洁。 :)
编辑:尽管我不确定这是否如此普遍,但我想到了一个误解。我听说一个项目经理说,单元测试使团队两次编写所有代码。如果看起来和感觉是那样,那么,我们就做错了。编写测试通常不仅可以加快开发速度,而且还为我们提供了一个方便的"现在我已经完成"的指示符,而我们本来没有其他的。
回答
我不同意Dan(尽管更好的选择可能只是不回答)...但是...
单元测试是编写代码以测试系统行为和功能的过程。
显然,测试可以提高代码的质量,但这只是单元测试的肤浅优势。真正的好处是:
- 在确保不更改行为(重构)的同时,更轻松地更改技术实现。可以对经过正确单元测试的代码进行积极的重构/清理,而几乎不会在不注意的情况下破坏任何内容。
- 在添加行为或者进行修复时使开发人员充满信心。
- 记录代码
- 指示代码中紧密耦合的区域。很难对紧密耦合的代码进行单元测试
- 提供一种使用API并尽早发现困难的方法
- 表示不太紧密的方法和类
我们应该进行单元测试,因为它符合利益,可以为客户提供可维护的优质产品。
我建议我们将其用于对现实行为进行建模的任何系统或者系统的一部分。换句话说,它特别适合于企业发展。我不会将其用于一次性/实用程序。我不会将其用于测试有问题的系统部分(UI是一个常见示例,但并非总是如此)
最大的陷阱是开发人员测试的单元太大,或者他们将方法视为单元。如果我们不了解控制反转,则尤其如此,在这种情况下,单元测试将始终转变为端到端集成测试。单元测试应该测试个体行为,并且大多数方法都有许多行为。
最大的误解是程序员不应该进行测试。只有糟糕或者懒惰的程序员才会相信这一点。盖屋顶的家伙不应该测试吗?更换心脏瓣膜的医生是否应该不测试新瓣膜?只有程序员才能测试他的代码是否达到了他的预期目的(QA可以测试被告知要执行程序员不希望的事情时的极端情况,客户可以进行验收测试,代码是否执行了什么工作?客户为此付费)
回答
这是我的看法。我会说单元测试是编写软件测试以验证真实软件是否达到了预期目的的一种做法。这始于Java世界中的jUnit,并已成为PHP中的最佳实践,以及SimpleTest和phpUnit。这是极限编程的核心实践,可以确保软件在编辑后仍能按预期运行。如果我们有足够的测试范围,则可以进行主要的重构,错误修复或者快速添加功能,而不必担心引入其他问题。
当所有单元测试都可以自动运行时,这是最有效的。
单元测试通常与OO开发相关。基本思想是创建一个脚本,该脚本为代码设置环境,然后对其进行练习。我们编写断言,指定应接收的预期输出,然后使用上述框架执行测试脚本。
框架将针对代码运行所有测试,然后报告每个测试的成功或者失败。 phpUnit默认情况下是从Linux命令行运行的,尽管有HTTP接口可用。 SimpleTest本质上是基于Web的,并且IMO易于安装和运行。与xDebug结合使用时,phpUnit可以为我们提供自动统计信息,以了解某些人认为非常有用的代码覆盖率。
一些团队从其Subversion存储库中编写钩子,以便在我们提交更改时自动运行单元测试。
最好将单元测试与应用程序放在同一存储库中。
回答
单元测试是对代码单元(例如单个功能)的测试,而无需该代码单元所依赖的基础结构。即单独进行测试。
例如,如果要测试的功能连接到数据库并进行更新,则在单元测试中,我们可能不想执行该更新。如果是集成测试,我们会这样做,但在这种情况下不是。
因此,单元测试将使用我们正在测试的"功能"中包含的功能,而不会产生数据库更新的副作用。
假设函数从数据库中检索了一些数字,然后执行了标准差计算。我们要在这里测试什么?是否正确计算了标准偏差或者从数据库返回了数据?
在单元测试中,我们只想测试标准偏差是否正确计算。在集成测试中,我们要测试标准偏差计算和数据库检索。
回答
我在FoxForward 2007上参加了有关单元测试的演示,并被告知永远不要对任何可用于数据的单元进行单元测试。毕竟,如果我们对实时数据进行测试,结果将是不可预测的,并且如果我们不对实时数据进行测试,则实际上并不是在测试编写的代码。不幸的是,这是我最近做的大部分编码。 :-)
最近,我在编写保存和恢复设置的例程时确实在TDD上拍过照片。首先,我确认可以创建存储对象。然后,它具有我需要调用的方法。然后,我可以称之为。然后,我可以传递参数。然后,我可以将其传递给特定参数。依此类推,直到我最终确认它可以保存指定的设置,然后允许我更改它,然后恢复它,以使用几种不同的语法。
我没有走到尽头,因为我需要立即执行常规操作,但这是一个很好的练习。
回答
What do you do if you are given a pile of crap and seem like you are stuck in a perpetual state of cleanup that you know with the addition of any new feature or code can break the current set because the current software is like a house of cards? How can we do unit testing then?
你从小开始。我刚刚进入的项目直到几个月前才进行过单元测试。当覆盖率很低时,我们只需选择一个没有覆盖率的文件,然后单击"添加测试"。
目前,我们的占比已超过40%,并且我们设法摘下了大多数低挂的水果。
(最好的部分是,即使覆盖率很低,我们也已经遇到了很多代码实例在做错事,而测试却抓住了它。这是促使人们增加更多测试的巨大动力。)
回答
在这里,我们将了解单元测试和TDD的哲学优势,其中一些是关键的"灯泡"观察,这让我震惊了我迈向TDD启蒙之路的初步尝试(无原创或者必然的消息)...
- TDD并不意味着编写两倍的代码量。测试代码通常编写起来非常快捷,轻松,并且是设计过程中至关重要的一部分,并且至关重要。
- TDD可实现何时停止编码!通过测试,我们可以确信自己已经做了足够的工作,并且可以停止调整并继续进行下一步。
- 测试和代码可以一起工作以获得更好的代码。代码可能是错误的/错误的。测试可能是错误/错误的。在TDD中,我们希望两者均处于劣势/越野车的几率很低。通常它的测试需要修复,但这仍然是一个很好的结果。
- TDD可帮助编码便秘。我们知道自己有很多事情要做,几乎不知道从哪里开始吗?这是星期五的下午,如果我们再拖延几个小时……TDD使我们可以快速充实自己认为需要做的事情,并使代码快速运行。另外,就像实验室的老鼠一样,我认为我们所有人都对那巨大的绿灯做出了反应,并且更加努力地再次看到它!
- 同样,这些设计师类型可以查看他们正在从事的工作。他们可以漫步去喝果汁/抽烟/ iphone,然后回到监视器,该监视器立即为他们提供到达目的地的视觉提示。 TDD给了我们类似的东西。当生活介入时,更容易看到我们要去的地方...
- 我认为正是福勒说:"经常运行的不完美测试比根本没有编写的完美测试要好得多"。我将其解释为允许我在我认为最有用的地方编写测试,即使余下的代码覆盖范围很不完整。
- TDD可以以各种令人惊讶的方式为我们提供帮助。好的单元测试可以帮助记录应该做什么,它们可以将代码从一个项目迁移到另一个项目,并给我们一种超越未测试同事的优越感:)
该演示文稿很好地介绍了所有可口的甜品测试所需要的内容。
回答
测试驱动开发已经取代了术语"单元测试"。作为旧计时器,我将提到它的更通用的定义。
单元测试还意味着测试大型系统中的单个组件。该单个组件可以是dll,exe,类库等。它甚至可以是多系统应用程序中的单个系统。因此,最终,单元测试最终将成为我们要调用的大型系统中的任何一个的测试。
然后,我们将通过测试所有组件的协同工作方式来进行集成或者系统测试。
回答
我使用单元测试来节省时间。
在构建业务逻辑(或者数据访问)时,测试功能通常可能涉及在许多可能尚未完成的屏幕中键入内容。使这些测试自动化可以节省时间。
对我来说,单元测试是一种模块化的测试工具。每个公共功能通常至少有一个测试。我编写了其他测试来涵盖各种行为。
我们在开发代码时想到的所有特殊情况都可以记录在单元测试的代码中。单元测试也成为有关如何使用代码的示例的来源。
对于我来说,发现我的新代码在单元测试中破坏了某些东西然后签入代码并让一些前端开发人员发现问题要快得多。
对于数据访问测试,我尝试编写不做任何更改或者自行清理的测试。
单元测试不能解决所有测试要求。他们将能够节省开发时间并测试应用程序的核心部分。
回答
使用Testivus。我们只需要知道就可以了:)
回答
我从来没有在大学里教过单元测试,并且花了我一段时间才"得到"它。我读了一下,说"啊,对,自动化测试,我想那可能很酷",然后我就忘记了。
在我真正弄清楚这一点之前,花了相当长的时间:假设我们在大型系统上工作,并且编写了一个小模块。它可以编译,通过它的步调,它可以很好地工作,然后继续执行下一个任务。下降了9个月,后来又发布了两个版本,其他人对程序中一些看似无关的部分进行了更改,从而中断了该模块。更糟糕的是,他们测试了自己的更改,代码也起作用了,但是他们没有测试模块。地狱,他们甚至可能不知道模块存在。
现在我们遇到了一个问题:损坏的代码在后备箱中,甚至没人知道。最好的情况是内部测试人员在我们发货之前就找到了它,但是修复游戏后期的代码很昂贵。而且,如果没有内部测试人员找到它,那么……的确会非常昂贵。
解决方案是单元测试。当我们编写好的代码时,它们会遇到问题,但我们可以手工完成。真正的收获是,当我们现在从事一个完全不同的项目时,它们将在9个月后发现问题,但夏季实习生认为,如果这些参数按字母顺序排列,然后进行单元测试,则看起来会更整齐。写回退失败,有人在实习生扔东西,直到他改变了参数顺序。这就是单元测试的"原因"。 :-)
回答
单元测试是关于编写测试应用程序代码的代码。
名称的Unit部分是关于一次测试小的代码单元(例如,一种方法)的意图。
xUnit可以帮助进行此测试,它们是可以帮助进行此测试的框架。其中一部分是自动测试运行程序,它告诉我们哪些测试失败以及哪些测试通过。
他们还具有在每次测试之前设置我们在每个测试中需要的通用代码以及在所有测试完成后将其拆解的功能。
我们可以进行测试以检查是否引发了预期的异常,而不必自己编写整个try catch块。
回答
与"只是打开一个新项目并测试此特定代码"相反,单元测试的主要区别在于它是自动化的,因此可重复。
如果我们手动测试代码,它可能会说服我们代码在当前状态下运行良好。但是大约一周后,如果我们对其进行了一些修改,该怎么办?我们是否愿意在代码中有任何更改时手动重新进行测试?最可能不是:-(
但是,如果我们可以在几秒钟内随时以完全相同的方式单击一次运行测试,那么只要出现问题,它们就会立即向我们显示。而且,如果我们还将单元测试集成到自动化的构建过程中,即使在看似完全不相关的更改中断了代码库中某个遥远的部分代码的情况下,即使我们根本不会想到它,它们也会提醒我们注意错误。需要重新测试该特定功能。
这是单元测试相对于手工测试的主要优势。但是,等等,还有更多:
- 单元测试极大地缩短了开发反馈循环:如果使用单独的测试部门,我们可能要花几周的时间才能知道代码中存在错误,而此时我们已经忘记了大部分上下文,因此可能要花几个小时才能完成。查找并修复错误; OTOH与单元测试,反馈周期以秒为单位,并且错误修复过程通常遵循"哦,我没在这里检查该条件"的字样:-)
- 单元测试有效地记录(对理解)代码的行为
- 单元测试迫使我们重新评估设计选择,从而使设计更简单,更简洁
反过来,单元测试框架使我们可以轻松编写和运行测试。
回答
单元测试是一种实践,可确保要实现的功能或者模块将按预期(要求)运行,并确保其在边界条件和无效输入等场景下的行为。
xUnit,NUnit,mbUnit等是可编写测试的工具。
回答
如果要使用肯特·贝克(Kent Beck)流行的TDD方法来开发项目,则像NUnit,xUnit或者JUnit这样的库只是强制性的:
我们可以阅读"测试驱动开发简介(TDD)"或者Kent Beck的书"测试驱动开发:示例"。
然后,如果要确保测试覆盖代码的"好"部分,则可以使用NCover,JCover,PartCover之类的软件。他们会告诉我们代码的覆盖率。根据我们对TDD的熟练程度,我们会知道自己是否做得足够好:)
回答
首先,无论是关于单元测试还是任何其他类型的自动化测试(集成,负载,UI测试等),与我们建议的主要区别在于它是自动化的,可重复的并且不需要任何人力资源被消耗掉(=无需执行测试,通常只需按一下按钮即可运行)。
回答
我认为我们不了解的是,像NUnit之类的单元测试框架将自动化中小型测试。通常,我们只需单击一个按钮,然后希望进度条保持绿色,即可在GUI中运行测试(例如,使用NUnit就是这种情况)。如果它变成红色,则框架会向我们显示哪个测试失败以及到底是什么错误。在正常的单元测试中,我们经常使用断言,例如" Assert.AreEqual(expectedValue,actualValue,"某些描述")),因此,如果两个值不相等,我们将看到一条错误消息:"某些描述:预期的<expectedValue>但为<actualValue>"。
因此,结论是,单元测试将使开发人员的测试速度更快,更舒适。我们可以在提交新代码之前运行所有单元测试,以免破坏其他开发人员在同一项目上的构建过程。
回答
我想推荐Gerard Meszaros撰写的《 xUnit测试模式》一书。它很大,但是在单元测试上是一个很好的资源。这是他网站的链接,其中他讨论了单元测试的基础。 http://xunitpatterns.com/XUnitBasics.html