Unit testing 什么是单元测试?

Unit testing 什么是单元测试?,unit-testing,Unit Testing,我看到很多问题问“如何”用特定语言进行单元测试,但没有问题问“什么”、“为什么”和“何时” 这是怎么一回事? 这对我有什么好处? 我为什么要用它? 我应该在什么时候使用它? 有哪些常见的陷阱和误解 粗略地说,单元测试是在与测试代码隔离的情况下测试代码的各个部分。我想到的直接好处是: 运行测试变得自动化和可重复 您可以通过GUI在比点击测试更细粒度的级别上进行测试 请注意,如果测试代码写入文件、打开数据库连接或通过网络执行某些操作,则更适合将其归类为集成测试。集成测试是一件好事,但不应与单元测试混

我看到很多问题问“如何”用特定语言进行单元测试,但没有问题问“什么”、“为什么”和“何时”

这是怎么一回事? 这对我有什么好处? 我为什么要用它? 我应该在什么时候使用它? 有哪些常见的陷阱和误解
粗略地说,单元测试是在与测试代码隔离的情况下测试代码的各个部分。我想到的直接好处是:

运行测试变得自动化和可重复 您可以通过GUI在比点击测试更细粒度的级别上进行测试 请注意,如果测试代码写入文件、打开数据库连接或通过网络执行某些操作,则更适合将其归类为集成测试。集成测试是一件好事,但不应与单元测试混淆。单元测试代码应该简短、甜美且执行迅速

看待单元测试的另一种方法是先编写测试。这就是所谓的测试驱动开发TDD。TDD带来了额外的优势:

您不必编写推测性的代码,我可能需要在将来的代码中使用它—只需足以使测试通过 您编写的代码总是包含在测试中 通过先编写测试,您不得不考虑如何调用代码,这通常会从长远来看改进代码的设计。 如果您现在没有进行单元测试,我建议您开始进行单元测试。得到一本好书,实际上任何一本xUnit的书都可以,因为它们之间的概念非常容易转移

有时编写单元测试会很痛苦。当它变成那样的时候,试着找人来帮助你,抵制住仅仅写该死的代码的诱惑。单元测试很像洗碗碟。这并不总是令人愉快的,但它让你的厨房保持干净,你真的希望它干净


编辑:我想到了一个误解,尽管我不确定它是否如此普遍。我听一位项目经理说,单元测试让团队将所有代码编写了两次。如果它看起来和感觉都是这样,那么,你做错了。编写测试不仅通常会加快开发速度,而且它还为您提供了一个方便的“现在我完成了”指示器,这是您在其他情况下无法做到的。

我不同意Dan的观点,尽管更好的选择可能是不回答……但是

单元测试是编写代码以测试系统行为和功能的过程

显然,测试可以提高代码的质量,但这只是单元测试的一个表面好处。真正的好处是:

使更改技术实现更容易,同时确保不更改重构行为。经过适当单元测试的代码可以被积极地重构/清理,几乎不可能在没有注意到的情况下破坏任何东西。 在添加行为或进行修复时给开发人员信心。 记录您的代码 指出代码中紧密耦合的区域。很难对紧密耦合的代码进行单元测试 提供一种使用API的方法,并在早期查找困难 指示内聚性不强的方法和类 您应该进行单元测试,因为向客户交付可维护且高质量的产品符合您的利益

我建议您将其用于模拟真实世界行为的任何系统或系统的一部分。换句话说,它特别适合企业开发。我不会将其用于一次性/实用程序。我不会将它用于测试UI有问题的系统部分,这是一个常见的例子,但情况并非总是如此

最大的缺陷是开发人员测试太大的单元,或者他们认为方法是单位。如果您不理解,这一点尤其正确——在这种情况下,您的单元测试将始终转变为端到端集成测试。单元测试应该测试个人行为——大多数方法都有很多行为


最大的误解是程序员不应该测试。只有糟糕或懒惰的程序员才会相信这一点。盖你屋顶的人不应该测试一下吗?更换心脏瓣膜的医生是否应该不测试新瓣膜?只有程序员才能测试他的代码是否做了他想做的事情QA可以测试边缘案例-当被告知做程序员不想做的事情时,代码的行为如何,客户可以做验收测试-代码是否做了客户花钱让它做的事这是我的看法。我想说的是,单元测试是编写软件测试的实践,以验证您的真实软件是否达到了预期目的。这始于Java世界,并已成为PHP以及和的最佳实践。它是极限编程的核心实践,帮助您确保您的软件在编辑后仍能按预期工作。如果您有足够的测试覆盖率,您可以快速地进行主要的重构、bug修复或添加特性,而不必担心引入其他问题

这是最有趣的 当所有单元测试都可以自动运行时有效

单元测试通常与OO开发相关联。基本思想是创建一个脚本,为代码设置环境,然后对其进行练习;编写断言,指定应该接收的预期输出,然后使用上述框架执行测试脚本

框架将针对您的代码运行所有测试,然后报告每个测试的成功或失败。默认情况下,phpUnit是从Linux命令行运行的,尽管有可用于它的HTTP接口。SimpleTest本质上是基于web的,并且更易于启动和运行,IMO。结合xDebug,phpUnit可以为您提供代码覆盖率的自动统计信息,有些人认为这非常有用

一些团队从subversion存储库中编写钩子,以便在提交更改时自动运行单元测试


将单元测试与应用程序放在同一个存储库中是一种很好的做法。

单元测试是对一个代码单元(例如单个功能)进行测试,而不需要该代码单元所依赖的基础结构。i、 e.隔离测试

例如,如果您正在测试的函数连接到数据库并执行更新,那么在单元测试中,您可能不希望执行该更新。如果它是一个集成测试,您会这样做,但在本例中不是

因此,单元测试将使用您正在测试的函数中包含的功能,而不会产生数据库更新的副作用

假设您的函数从数据库中检索到一些数字,然后执行标准偏差计算。你想在这里测试什么?是否正确计算了标准偏差,或是否从数据库返回了数据


在单元测试中,您只需要测试标准偏差的计算是否正确。在集成测试中,您希望测试标准偏差计算和数据库检索。

我参加了FoxForward 2007的单元测试演示,被告知永远不要对任何与数据相关的东西进行单元测试。毕竟,如果您在实时数据上进行测试,结果是不可预测的,如果您不在实时数据上进行测试,那么您实际上并不是在测试您编写的代码。不幸的是,这是我这些天做的大部分编码-

最近,我在写一个保存和恢复设置的例程时,确实尝试过TDD。首先,我验证了我可以创建存储对象。然后,它有了我需要调用的方法。然后,我可以称之为。然后,我可以传递它的参数。然后,我可以传递它特定的参数。依此类推,直到我最终验证它是否会保存指定的设置,允许我更改它,然后为几个不同的语法恢复它

我没有结束,因为我现在需要常规训练,该死,但这是一个很好的锻炼

如果给你一堆废话,你会怎么做?如果你似乎陷入了一种永久性的清理状态,你知道添加任何新功能或代码都会破坏当前设置,因为当前的软件就像一个纸牌屋

那么我们如何进行单元测试呢

你从小事做起。我刚刚进入的项目直到几个月前才进行单元测试。当覆盖率很低时,我们只需选择一个没有覆盖率的文件,然后单击AddTests

现在我们已经超过了40%,而且我们已经成功地摘下了大部分低垂的果实


最好的部分是,即使在这种低覆盖率的情况下,我们已经遇到了许多代码做错事的实例,测试发现了这一点。这是促使人们增加更多测试的巨大动力。

这里是一些关于单元测试和TDD的哲学优势的关键灯泡观察,这些观察让我在通向TDD启蒙的道路上迈出了试探性的第一步——不是原创的,也不一定是新闻

TDD并不意味着要写两倍的代码。测试代码通常编写起来相当快速和轻松,并且是设计过程的关键部分,而且非常关键

TDD帮助您了解何时停止编码!你的测试给你信心,你已经做了足够的现在,可以停止调整,并继续下一件事

测试和代码一起工作以获得更好的代码。您的代码可能是错误的/错误的。你的测试可能不好/有问题。在TDD中,您指望的是坏/坏的可能性都相当低。通常这是一个需要修正的测试,但这仍然是一个好结果

TDD有助于编码便秘。你知道那种感觉,你有那么多事情要做,你几乎不知道从哪里开始?今天是星期五下午,如果你再拖延几个小时。。。TDD允许您非常快速地充实您认为需要做的事情,并使您的代码快速运行。还有,就像实验室里的老鼠一样,我想我们都会对那个大绿灯和 努力工作,让它再次出现

类似地,这些设计师类型可以看到他们在做什么。他们可以出去喝果汁、抽烟、玩iphone,然后回到显示器前,显示器会立即给他们一个视觉提示,告诉他们去了哪里。TDD给了我们类似的东西。当生活介入时,我们更容易看到我们的处境

我想是Fowler说的:经常运行的不完美测试要比从不编写的完美测试好得多。我将此解释为允许我编写我认为最有用的测试,即使我的其余代码覆盖范围非常不完整

TDD以各种令人惊讶的方式提供帮助。好的单元测试可以帮助记录某件事情应该做什么,它们可以帮助您将代码从一个项目迁移到另一个项目,并给您带来一种比不进行测试的同事更优越的感觉:


是一个非常好的介绍,介绍了所有的美味佳肴测试。

测试驱动开发已经取代了单元测试这个术语。作为一个老前辈,我会提到它更一般的定义

单元测试还意味着在更大的系统中测试单个组件。这个组件可以是dll、exe、类库等。它甚至可以是多系统应用程序中的单个系统。因此,单元测试最终是对任何你想称之为更大系统的单个部分的测试


然后,您可以通过测试所有组件如何协同工作,进而进行集成或系统测试

我使用单元测试来节省时间

在构建业务逻辑或数据访问测试功能时,通常需要在许多屏幕中键入内容,这些内容可能尚未完成,也可能尚未完成。自动化这些测试可以节省时间

对我来说,单元测试是一种模块化的测试工具。通常每个公共函数至少有一个测试。我写了额外的测试来涵盖各种行为

开发代码时想到的所有特殊情况都可以记录在单元测试的代码中。单元测试也成为如何使用代码的示例来源

对我来说,在单元测试中发现我的新代码破坏了某些东西,然后检入代码并让一些前端开发人员发现问题的速度要快得多

对于数据访问测试,我尝试编写没有更改或自己清理的测试


单元测试不能解决所有的测试需求。他们将能够节省开发时间并测试应用程序的核心部分。

使用。你需要知道的就是:

我在大学里从来没有学过单元测试,我花了一段时间才学会。我读到它,去了,啊,对了,自动化测试,我想那可能很酷,然后我就忘了

我花了相当长的时间才真正明白这一点:假设你在一个大系统上工作,你写了一个小模块。它可以编译,你可以按照它的速度进行测试,它工作得很好,你可以继续下一个任务。九个月后,两个版本之后,其他人对程序中看似不相关的部分进行了更改,这打破了模块。更糟糕的是,他们测试他们的更改,他们的代码工作,但他们不测试您的模块;见鬼,他们甚至可能不知道你的模块存在

现在你遇到了一个问题:坏代码在后备箱里,甚至没有人知道。最好的情况是内部测试人员在您发布之前找到它,但是在游戏后期修复代码是昂贵的。如果没有内部测试人员发现它…那么,这可能会变得非常昂贵


解决方案是单元测试。当您编写代码时,他们会发现问题——这很好——但您可以手工完成。真正的回报是,当你现在从事一个完全不同的项目时,他们会在接下来的九个月内发现问题,但一名暑期实习生认为,如果这些参数按字母顺序排列,那么看起来会更整洁——然后你写的单元测试失败了,有人向实习生扔东西,直到他改变参数顺序。这就是单元测试的原因:-

单元测试是关于编写测试应用程序代码的代码

名称的单元部分是关于一次测试一个方法的小代码单元的意图

xUnit是用来帮助测试的——它们是帮助测试的框架。其中一部分是自动测试运行程序,它告诉您哪些测试失败,哪些通过

他们还可以在每次测试之前设置您需要的公共代码,并在所有测试完成后将其删除


您可以进行一个测试来检查是否抛出了预期的异常,而不必自己编写整个try-catch块。

单元测试的主要区别在于它是自动化的,因此可以重复 e

如果您手动测试代码,它可能会让您相信代码在当前状态下工作得很好。但是一周后,当你对它做了一个小小的修改时呢?当代码中发生任何更改时,您是否愿意手动重新测试它?很可能不是:-

但是,如果您可以在任何时候运行测试,只需单击一次,完全相同的方式,在几秒钟内,那么无论什么时候出现故障,它们都会立即显示给您。如果您还将单元测试集成到您的自动构建过程中,那么即使在一个看似完全不相关的更改破坏了代码库的某个遥远部分的情况下,单元测试也会向您发出错误警报,而您甚至不会想到需要重新测试该特定功能

这是单元测试相对于手工测试的主要优势。但等等,还有更多:

单元测试极大地缩短了开发反馈循环:如果有一个单独的测试部门,您可能需要几周的时间才能知道代码中有一个bug,到那时您已经忘记了很多上下文,因此可能需要几个小时才能找到并修复bug;在单元测试中,反馈周期以秒为单位,bug修复过程通常是沿着oh-sh*t的路线进行的,我忘了在这里检查这种情况:- 单元测试有效地记录了您对代码行为的理解 单元测试迫使您重新评估您的设计选择,这将导致更简单、更干净的设计
反过来,单元测试框架使您编写和运行测试变得更加容易。

单元测试是一种实践,用于确保您要实现的功能或模块将按照预期的要求运行,并确保其在边界条件和无效输入等情况下的行为

、、等是帮助您编写测试的工具。

如果您想使用Kent Beck推广的方法开发项目,则类库是必需的:

你可以读或读肯特·贝克的书


然后,如果你想确保你的测试覆盖了你代码的一部分,你可以使用软件,比如,或者别的什么。他们会告诉你代码的覆盖率。取决于您对TDD的熟练程度,您将知道您是否已经足够熟练地实践了它:

首先,无论是关于单元测试还是任何其他类型的自动化测试集成、负载、UI测试等,与您建议的关键区别在于它是自动化的,可重复且不需要消耗任何人力资源=没有人必须执行测试,它们通常只需按一个按钮即可运行。

我认为您不了解的一点是,NUnit等单元测试框架将帮助您自动化中小型测试。通常,您可以在GUI中运行测试,例如,只需单击一个按钮,然后(希望如此)看到进度栏保持绿色。如果它变为红色,框架将向您显示哪个测试失败,以及到底出了什么问题。在正常的单元测试中,您经常使用断言,例如Assert.arequalexpectedvalue、actualValue、some description-因此,如果这两个值不相等,您将看到一个错误,显示some description:expected but was


因此,作为结论,单元测试将使开发人员的测试更快、更舒适。在提交新代码之前,您可以运行所有的单元测试,这样就不会破坏同一项目中其他开发人员的构建过程。

我想推荐Gerard Meszaros的《xUnit测试模式》一书。它很大,但在单元测试方面是一个很好的资源。这里是他的网站的链接,他在那里讨论了单元测试的基础知识

这回答了为什么应该进行单元测试

下面的3个视频介绍了javascript中的单元测试,但一般原则适用于大多数语言

单元测试:现在只需几分钟就能节省几个小时-Eric Mann-

JS单元测试非常好-

编写可测试JavaScript-

现在我只是在学习这个主题,所以我可能不是100%正确的,这比我在这里描述的要多,但我对单元测试的基本理解是,您编写一些测试代码,这些代码与主代码分开,主代码使用函数所需的输入参数调用主代码中的函数,然后再编写代码检查它是否返回有效的返回值。如果它确实返回了一个有效值,那么用于运行测试的单元测试框架将显示一个绿灯。如果该值无效,则会显示一个红灯。然后,在将新代码发布到生产环境之前,您可以立即修复该问题,而不进行测试,您可能实际上没有发现错误

因此,您需要为当前代码编写测试,并创建代码以使其通过测试。几个月后,您或其他人需要修改y中的函数 我们的主代码,因为之前您已经为该函数编写了测试代码,现在再次运行,测试可能会失败,因为编码器在函数中引入了逻辑错误,或者返回了与该函数应该返回的完全不同的内容。同样,如果没有适当的测试,该错误可能很难跟踪,因为它可能也会影响其他代码,并且会被忽略

另外,您有一个运行代码并对其进行测试的计算机程序,而不是在浏览器中逐页手动进行测试,这一事实节省了javascript单元测试的时间。假设您修改了某个web页面上的脚本所使用的函数,并且该函数可以很好地满足其新的预期用途。但是,为了参数起见,我们还可以说,代码中的其他地方还有另一个函数,它依赖于新修改的函数来正常运行。由于您对第一个函数所做的更改,此依赖函数现在可能会停止工作,但是,如果没有由计算机自动运行的测试,在实际执行该功能之前,您不会注意到该功能存在问题,并且您必须手动导航到包含执行从属功能的脚本的网页,只有这样,您才会注意到由于对第一个函数所做的更改而出现了一个bug

重申一下,在开发应用程序时运行测试将在编写代码时发现此类问题。如果没有适当的测试,您将不得不手动检查整个应用程序,即使这样,也很难发现错误,您天真地将其发送到生产环境中,过了一段时间,一位善良的用户会向您发送一份错误报告,该报告不如测试框架中的错误消息好

当您第一次听到这个主题时,您会感到非常困惑,您会想,我是否已经在测试我的代码了?你所写的代码已经像预期的那样工作了,为什么我需要另一个框架?。。。是的,你已经在测试你的代码了,但是计算机在这方面做得更好。您只需为一个函数/代码单元编写一次足够好的测试,其余的测试由强大的cpu处理,而不必在更改代码时手动检查所有代码是否仍在工作


此外,如果您不想对代码进行单元测试,您也不必对代码进行单元测试,但随着引入bug的机会增加,您的项目/代码库开始变得越来越大,这会带来回报。

通常,单元测试和TDD可以缩短您编写的软件的反馈周期。与在实现的最后有一个大型测试阶段不同,您可以增量地测试您编写的所有内容。这大大提高了代码质量,正如您马上看到的,您可能会有bug。

+1此外,我最喜欢的部分是关于测试代码的,尤其是当给定一个新的代码库时:它演示了测试代码的预期用途。优步,有很多可用的资源,当然是一个很好的起点。一旦你有了一个基本的想法,也许一些更具体的问题可以帮助你自己决定是否要使用单元测试。这是5个宽泛的问题。幸好你问了这个问题,与阅读在线资源相比,阅读一个在职程序员的答案要好得多。你能进一步阐述你关于TDD如何加速开发的观点吗?