关于词汇表:什么是单元测试?

What is unit testing?

我看到很多问题询问'如何'用特定的语言进行单元测试,但毫无疑问,问'什么','为什么'和'什么时候'。

  • 它是什么?
  • 它对我有什么用?
  • 我为什么要用它?
  • 我什么时候应该使用它(当不是时)?
  • 有哪些常见的陷阱和错误观念


粗略地说,单元测试是用测试代码单独测试代码的一部分。想到的直接好处是:

  • 运行测试变得可自动化且可重复
  • 您可以通过GUI进行比点击式测试更精细的测试

请注意,如果您的测试代码写入文件,打开数据库连接或通过网络执行某些操作,则更适合将其归类为集成测试。集成测试是一件好事,但不应与单元测试混淆。单元测试代码应该简短,甜蜜且快速执行。

查看单元测试的另一种方法是首先编写测试。这被称为测试驱动开发(简称TDD)。 TDD带来了额外的优势:

  • 你不会写出推测性的"我将来可能需要这个"代码 - 这足以让测试通过
  • 您编写的代码总是由测试覆盖
  • 通过首先编写测试,您不得不考虑如何调用代码,从长远来看,这通常会改进代码的设计。

如果您现在没有进行单元测试,我建议您开始使用它。得到一本好书,几乎任何xUnit-book都会做,因为这些概念在它们之间是可以转移的。

有时编写单元测试可能会很痛苦。当它成功的时候,试着找人来帮助你,并抵制"只写那该死的代码"的诱惑。单元测试就像洗碗一样。它并不总是令人愉快,但它让你的隐喻厨房变得干净,你真的希望它变得干净。 :)

编辑:脑海中浮现出一种误解,虽然我不确定它是否如此常见。我听说项目经理说单元测试让团队编写了两次所有代码。如果它看起来和感觉那样,那么,你做错了。编写测试通常不仅可以加快开发速度,而且还可以为您提供一个方便的"现在我已经完成"的指标,否则您就不会这样做。


我不同意丹(虽然更好的选择可能只是不回答)......但......

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

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

  • 在确保不改变行为(重构)的同时,更容易更改技术实现。正确的单元测试代码可以被积极地重构/清理,几乎没有机会在不注意的情况下破坏任何东西。
  • 在添加行为或修复时为开发人员提供信心。
  • 记录您的代码
  • 指示代码紧密耦合的区域。单元测试紧密耦合的代码很难
  • 提供一种使用API??的方法,并尽早寻找困难
  • 表示不具有凝聚力的方法和类
  • 您应该进行单元测试,因为您有兴趣为您的客户提供可维护和优质的产品。

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

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

    最大的误解是程序员不应该测试。只有糟糕或懒惰的程序员才会相信。建造屋顶的人不应该测试吗?更换心脏瓣膜的医生是否应该测试新的瓣膜?只有程序员才能测试他的代码是否按照他的意图进行测试(QA可以测试边缘情况 - 代码在被告知做程序员不想要的事情时的行为,客户端可以进行验收测试 - 代码是否执行客户支付的费用是什么)


    与"仅打开一个新项目并测试此特定代码"相反,单元测试的主要区别在于它是自动化的,因此是可重复的。

    如果您手动测试代码,它可能会让您确信代码运行正常 - 处于当前状态。但是一周后,当你对它做了一点修改时呢?您是否愿意在代码中发生任何变化时再次手动重新测试?最有可能不是:-(

    但是,如果您可以随时运行测试,只需单击一次,几秒钟内完全相同,那么无论何时出现问题,他们都会立即向您显示。如果你还将单元测试集成到你的自动构建过程中,他们会提醒你注意错误,即使在一个看似完全不相关的变化破坏了代码库的一个遥远的部分 - 甚至在你甚至不会发生的情况下需要重新测试该特定功能。

    这是单元测试优于手动测试的主要优点。但等等,还有更多:

    • 单元测试显着缩短了开发反馈循环:对于单独的测试部门,您可能需要数周时间才能知道代码中存在错误,此时您已经忘记了大部分上下文,因此可能需要数小时才能完成找到并修复bug; OTOH通过单元测试,反馈周期以秒为单位进行测量,错误修复过程通常沿着"哦sh * t,我忘了检查这个条件":-)
    • 单元测试有效地记录(您的理解)代码的行为
    • 单元测试迫使您重新评估您的设计选择,从而使设计更简单,更清洁

    反过来,单元测试框架使您可以轻松编写和运行测试。


    我从未在大学教过单元测试,我花了一段时间才"搞定"它。我读到了它,"啊,对,自动测试,我觉得这很酷",然后我就忘记了。

    在我真正弄清楚这一点之前花了相当长的时间:让我们说你正在研究一个大型系统并且你编写了一个小模块。它编译,你通过它的步伐,它工作得很好,你继续下一个任务。九个月后,有两个版本,其他人改变了一些看似无关的程序部分,它打破了模块。更糟糕的是,他们测试他们的更改,他们的代码是有效的,但他们不测试你的模块;他们甚至不知道你的模块是否存在。

    而现在你遇到了一个问题:破解的代码在主干中,甚至没有人知道。最好的情况是内部测试人员在您发货之前找到它,但修复游戏后期的代码是昂贵的。如果没有内部测试人员发现它......那么,确实会变得非常昂贵。

    解决方案是单元测试。当你编写代码时,它们会遇到问题 - 这很好 - 但你可以手工完成。真正的回报是,当你现在正在开展一个完全不同的项目时,他们会在九个月后遇到问题,但是一个暑期实习生认为如果这些参数按字母顺序排列会更整洁 - 然后是单元测试你写回来的方法失败了,有人向实习生抛出东西,直到他改变参数顺序为止。这就是单元测试的"原因"。 :-)


    关于单元测试和TDD的哲学专业知识,这里有一些关键的"灯泡"观察,这些观察让我在TDD启蒙的道路上暂时迈出了初步的步伐(没有原创或必然的消息)......

  • TDD并不意味着写入两倍的代码量。测试代码通常可以非常快速且轻松地编写,并且是设计过程的关键部分,也是批判性的。

  • TDD可以帮助您实现何时停止编码!你的测试让你相信你已经做了足够的事情,可以停止调整并继续下一步。

  • 测试和代码协同工作以实现更好的代码。你的代码可能很糟糕/错误。你的测试可能很糟糕/错误。在TDD中,你可以看出两个人很差/错误的可能性很小。通常它的测试需要修复,但仍然是一个很好的结果。

  • TDD有助于编码便秘。你知道那种感觉你有很多事要做,你几乎不知道从哪里开始?这是星期五下午,如果你拖延几个小时...... TDD可以让你很快充实你认为你需要做的事情,并让你的编码迅速发展。此外,就像实验室老鼠一样,我想我们都会回应那个大绿灯,并且更加努力地再次看到它!

  • 同样,这些设计师类型可以看到他们正在做的工作。他们可以徘徊在果汁/香烟/ iphone休息时间,并返回显示器,立即给他们一个关于他们到达的地方的视觉提示。 TDD给了我们类似的东西。生活介入时,我们更容易看到我们到达的地方......

  • 我认为Fowler说:"不完美的测试,经常运行,比完全没有写过的完美测试要好得多"。我将此解释为允许我编写测试,即使我的其余代码覆盖率非常不完整,我认为它们也是最有用的。

  • TDD以各种令人惊讶的方式提供帮助。良好的单元测试可以帮助记录应该做的事情,它们可以帮助您将代码从一个项目迁移到另一个项目,并给您一种无理感的优势,而不是非测试同事:)

  • 本演示文稿是对所有美味良好测试需求的精彩介绍。


    我想推荐Gerard Meszaros的xUnit Testing Patterns一书。它很大但是在单元测试方面是一个很好的资源。这是他的网站的链接,他在那里讨论了单元测试的基础知识。 http://xunitpatterns.com/XUnitBasics.html


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

    在构建业务逻辑(或数据访问)时,测试功能通常涉及在很多可能已完成或可能尚未完成的屏幕中输入内容。自动化这些测试可节省时间。

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

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

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

    对于数据访问测试,我尝试编写无需更改或自行清理的测试。

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


    如果您想使用Kent Beck推广的TDD方法开发项目,那么像NUnit,xUnit或JUnit这样的图标馆是强制性的:

    您可以阅读测试驱动开发简介(TDD)或Kent Beck的书"测试驱动开发:示例"。

    然后,如果您想确保您的测试涵盖代码的"好"部分,您可以使用NCover,JCover,PartCover等软件。他们会告诉你代码的覆盖率。根据你对TDD的熟练程度,你会知道你是否已经练习得很好:)


    这是我的看法。我会说单元测试是编写软件测试的实践,以验证您的真实软件是否符合它的意图。这开始于Java世界中的jUnit,并且已经成为PHP中的最佳实践,以及SimpleTest和phpUnit。它是极限编程的核心实践,可帮助您确保软件在编辑后仍能按预期工作。如果您有足够的测试覆盖率,您可以快速进行重构,修复错误或添加功能,而不必担心引入其他问题。

    当所有单元测试都可以自动运行时,它是最有效的。

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

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

    有些团队从他们的subversion存储库编写钩子,以便在您提交更改时自动运行单元测试。

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


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

    xUnit,NUnit,mbUnit等是帮助您编写测试的工具。


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

    名称的单位部分是关于一次测试小单位代码(例如一种方法)的意图。

    xUnit可以帮助进行这项测试 - 它们是帮助实现这一目标的框架。其中一部分是自动测试运行器,它告诉您哪些测试失败以及哪些测试失败。

    它们还具有在每个测试中设置您需要的公共代码的功能,并在所有测试完成后将其拆除。

    您可以进行测试以检查是否已抛出预期的异常,而无需自己编写整个try catch块。


    我认为您不理解的一点是,像NUnit(等)这样的单元测试框架将帮助您实现中小型测试的自动化。通常你可以在GUI中运行测试(例如NUnit就是这种情况),只需单击一个按钮,然后 - 希望 - 看到进度条保持绿色。如果它变为红色,框架会显示哪个测试失败以及究竟出了什么问题。在正常的单元测试中,您经常使用断言,例如Assert.AreEqual(expectedValue, actualValue,"some description") - 所以如果这两个值不相等,你会看到一个错误,说"有些描述:期望但是是"。

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


    单元测试是对代码单元(例如单个函数)的测试,而不需要该代码单元所依赖的基础结构。即单独测试。

    例如,如果您正在测试的函数连接到数据库并进行更新,则在单元测试中您可能不希望进行该更新。如果它是集成测试你会,但在这种情况下,它不是。

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

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

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


    使用Testivus。所有你需要知道的就是那里:)


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


    测试驱动开发有点接受单元测试这个术语。作为一个旧计时器,我将提到它的更通用的定义。

    单元测试还意味着在更大的系统中测试单个组件。这个单独的组件可以是dll,exe,类库等。它甚至可以是多系统应用程序中的单个系统。因此,最终单元测试最终将测试您想要称为单个较大系统的任何内容。

    然后,您将通过测试所有组件如何协同工作来升级到集成或系统测试。


    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%以上,而且我们已经成功地剔除了大多数悬而未决的成果。

    (最好的部分是,即使在这种低覆盖率的情况下,我们已经遇到了许多错误的代码实例,测试也抓住了它。这是推动人们添加更多测试的巨大动力。)


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

    最近,当我编写保存和恢复设置的例程时,我确实对TDD进行了拍摄。首先,我验证了我可以创建存储对象。然后,它有我需要调用的方法。然后,我可以称之为。然后,我可以传递它参数。然后,我可以传递它特定的参数。依此类推,直到我最终确认它将保存指定的设置,允许我更改它,然后恢复它,用于几种不同的语法。

    我没有达到目的,因为我需要 - 例行 - 现在 - 该死,但这是一个很好的练习。


    这就解释了为什么你应该进行单元测试。

    以下3个视频涵盖了javascript中的单元测试,但一般原则适用于大多数语言。

    单元测试:几分钟后将节省数小时 - Eric Mann - https://www.youtube.com/watch?v=_UmmaPe8Bzc

    JS单元测试(非常好) - https://www.youtube.com/watch?v=-IYqgx8JxlU

    编写可测试的JavaScript - https://www.youtube.com/watch?v=OzjogCFO4Zo

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

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

    此外,您拥有一个运行代码并测试它的计算机程序而不是您在浏览器中逐页手动执行它的事实可以节省时间(单元测试javascript)。假设您修改了网页上某些脚本使用的函数,它可以很好地工作并且有利于其新的预期目的。但是,为了论证,我们还要说你的代码中还有另一个函数依赖于新修改的函数来使其正常运行。由于您对第一个函数所做的更改,此依赖函数现在可能会停止工作,但是如果没有由您的计算机自动运行的测试,您将不会注意到该函数在实际执行之前存在问题。您必须手动导航到包含执行相关功能的脚本的网页,然后您才会注意到由于您对第一个功能所做的更改而存在错误。

    重申一下,在开发应用程序时运行测试会在编码时遇到这些问题。如果没有测试,您必须手动完成整个应用程序,即使这样,也很难发现错误,天真地将它发送到生产中,过了一段时间,一个善意的用户会向您发送错误报告(其中将不会像测试框架中的错误消息一样好。

    当你第一次听到这个主题并且你想到自己时,这是非常令人困惑的,我还没有测试过我的代码吗?你编写的代码就像它应该已经工作一样,"为什么我需要另一个框架?"...是的,你已经在测试你的代码,但计算机更擅长这样做。你只需要为一个函数/代码单元编写足够好的测试一次,其余的由强大的cpu为你处理,而不是你必须手动检查你的所有代码是否仍然有效你的代码。

    此外,如果您不想对代码进行单元测试,但随着项目/代码库开始变大,随着引入错误的机会增加,您无需付出代价。


    单元测试和TDD通常使您可以缩短关于所编写软件的反馈周期。 您不必在实施的最后阶段进行大量测试,而是逐步测试您编写的所有内容。 这会极大地提高代码质量,如您所见,您可能会遇到错误。