glossary -什么是单元测试?

Translate

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

  • 它是什么?
  • 它对我有什么作用?
  • 我为什么要使用它?
  • 我什么时候应该使用它?
  • 有哪些常见的陷阱和误解
This question and all comments follow the "Attribution Required."

所有的回答

Translate

粗略地说,单元测试是与测试代码隔离地测试代码的各个部分。我想到的直接好处是:

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

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

查看单元测试的另一种方法是先编写测试。这就是所谓的测试驱动开发(TDD)。 TDD具有其他优势:

  • 您无需编写推测性的“将来可能需要”代码,仅足以使测试通过
  • 您编写的代码始终包含在测试中
  • 通过首先编写测试,您不得不考虑如何调用代码,从长远来看,这通常可以改善代码的设计。

如果您现在不进行单元测试,建议您开始使用它。获得一本好书,几乎任何xUnit-book都可以做,因为这些概念之间可以很容易地转移。

有时编写单元测试会很痛苦。当这种方式得到解决时,请尝试寻找可以帮助您的人,并抵制“只写该死的代码”的诱惑。单元测试很像洗碗。它并不总是那么令人愉快,但是它可以使您的隐喻厨房保持清洁,并且您真的希望它保持清洁。 :)


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

来源
Translate

我不同意Dan(尽管更好的选择可能只是不回答)...但是...

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

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

  1. 在确保不更改行为(重构)的同时,更轻松地更改技术实现。可以对经过正确单元测试的代码进行积极地重构/清理,而几乎不会在不注意的情况下破坏任何内容。
  2. 在添加行为或进行修复时使开发人员充满信心。
  3. 记录您的代码
  4. 指示代码中紧密耦合的区域。很难对紧密耦合的代码进行单元测试
  5. 提供一种使用API并尽早发现困难的方法
  6. 指示不太紧密的方法和类

您应该进行单元测试,因为它符合您的利益,可以为客户提供可维护的优质产品。

我建议您将其用于对现实行为进行建模的任何系统或系统的一部分。换句话说,它特别适合企业发展。我不会将其用于一次性/实用程序。我不会将其用于测试有问题的系统部分(UI是一个常见示例,但并非总是如此)

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

最大的误解是程序员不应进行测试。只有糟糕或懒惰的程序员才会相信这一点。盖屋顶的家伙不应该测试吗?更换心脏瓣膜的医生是否应该不测试新瓣膜?只有程序员才能测试他的代码是否达到了他的预期目的(QA可以测试极端情况-告诉他们要做程序员不希望的事情时代码的行为,客户可以进行验收测试-代码可以做到吗客户为此支付了什么费用)

来源
Translate

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

如果您手动测试代码,它可能会说服您代码运行良好-目前状态。但是大约一周后,当您对其进行了轻微修改时,该怎么办?您是否愿意随时手动重新测试任何东西您的代码有变化吗?可能不是:-(

但是如果可以的话几秒钟内完全相同的方式,只需单击一下即可运行测试, 然后他们如有任何损坏,请立即向您显示。而且,如果您还将单元测试集成到自动化的构建过程中,即使在看似完全不相关的更改在代码库的遥远部分破坏了某些内容的情况下,它们也会提醒您注意错误-当您什至不会想到需要重新测试该特定功能。

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

  • 单元测试缩短开发反馈循环引人注目的是:在单独的测试部门,您可能需要数周的时间才能知道代码中存在错误,而此时您已经忘记了大部分上下文,因此可能需要数小时才能找到并修复错误; OTOH与单元测试,反馈周期以秒为单位,并且错误修复过程通常遵循“哦,我没在这里检查该条件”的字样:-)
  • 有效地进行单元测试文件(您的理解)代码的行为
  • 单元测试迫使您重新评估设计选择,从而导致更简单,更清洁的设计

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

来源
Translate

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

在我真正弄清楚这一点之前,花了相当长的时间:假设您在大型系统上工作,并且编写了一个小模块。它可以编译,通过它的步调,它可以很好地工作,然后继续执行下一个任务。下线了9个月,后来又有两个版本的人对某些版本进行了更改似乎程序的无关部分,它破坏了模块。更糟糕的是,他们测试了自己的更改,代码也起作用,但是他们没有测试您的模块。地狱,他们甚至可能都不知道您的模块存在.

现在您遇到了一个问题:损坏的代码在后备箱中,甚至没人知道。最好的情况是内部测试人员在您发货之前就找到了它,但是在游戏后期修复代码很昂贵。而且,如果没有内部测试人员找到它,那么……的确会非常昂贵。

解决方案是单元测试。当您编写代码时,它们会遇到问题-很好-但是您可以手工完成。真正的收获是,当您现在从事一个完全不同的项目时,他们将在9个月后发现问题,但是一个暑期实习生认为,如果这些参数按字母顺序排列,则看起来会更整洁-然后进行单元测试您写的返回失败,并且有人在实习生扔东西,直到他更改了参数顺序。那是单元测试的“为什么”。 :-)

来源
Translate

在这里,您将了解单元测试和TDD的哲学优势,其中一些是关键的“灯泡”观察,这使我震惊了我迈向TDD启蒙之路的初步尝试(没有原创或必然的消息)...

  1. TDD并不意味着编写两倍的代码量。测试代码通常编写起来非常快捷,轻松,并且是设计过程中至关重要的一部分,并且至关重要。

  2. TDD可帮助您实现何时停止编码!通过测试,您可以确信自己已经做了足够的工作,并且可以停止调整并继续进行下一步。

  3. 测试和代码可以一起工作以获得更好的代码。您的代码可能是错误的/错误的。您的测试可能是错误/错误的。在TDD中,您希望同时降低不良率/越野车的可能性。通常,它的测试需要修复,但这仍然是一个很好的结果。

  4. TDD帮助便秘编码。您知道自己有很多事情要做,几乎不知道从哪里开始吗?这是星期五的下午,如果您再拖延几个小时……TDD使您可以快速充实自己认为需要做的事情,并使代码快速运行。另外,就像实验室的老鼠一样,我认为我们所有人都对那巨大的绿灯做出了反应,并努力工作才能再次看到它!

  5. 同样,这些设计师类型可以查看他们正在从事的工作。他们可以流连忘返,喝点果汁/抽烟/ iphone,然后回到监视器,该监视器立即为他们提供到达目的地的视觉提示。 TDD给了我们类似的东西。当生活介入时,更容易看到我们去了哪里...

  6. 我认为正是福勒说:“经常运行的不完美测试比根本没有编写的完美测试要好得多”。我认为这是允许我在我认为最有用的地方编写测试,即使我的其余代码覆盖范围很不完整。

  7. TDD可以以各种令人惊讶的方式为您提供帮助。好的单元测试可以帮助记录应该做什么,它们可以帮助您将代码从一个项目迁移到另一个项目,并且给您一种超越非测试同事的优越感:)

本演讲是对所有美味甜品测试所必需的出色介绍。

来源
Translate

我想推荐Gerard Meszaros撰写的《 xUnit测试模式》一书。它很大,但是在单元测试上是一个很好的资源。这是他网站的链接,其中他讨论了单元测试的基础。http://xunitpatterns.com/XUnitBasics.html

来源
Translate

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

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

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

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

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

对于数据访问测试,我尝试编写不做任何更改或自行清理的测试。

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

来源
Translate

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

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

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

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

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

最好将单元测试与应用程序放在同一存储库中。

来源
Translate

图书馆喜欢NUnit, 单位要么JUnit的如果您想使用TDD肯特·贝克(Kent Beck)推广的方法:

你可以阅读测试驱动开发(TDD)简介或肯特·贝克的书测试驱动开发:通过示例.

然后,如果您想确保测试覆盖了代码的“良好”部分,则可以使用类似NCover, JCover, PartCover管他呢。他们会告诉您代码的覆盖率。根据您对TDD的熟练程度,您会知道自己是否做得足够好:)

来源
Guy
Translate

单元测试是对代码单元(例如,单个功能)的测试,而无需该代码单元所依赖的基础结构。即单独进行测试。

例如,如果要测试的功能连接到数据库并进行更新,则在单元测试中,您可能不想执行该更新。如果是集成测试,您会这样做,但在这种情况下不是。

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

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

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

来源
Translate

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

单元该名称的一部分与打算一次测试小的代码单元(例如一种方法)有关。

xUnit可以帮助进行此测试-它们是有助于此测试的框架。其中一部分是自动测试运行程序,它告诉您哪些测试失败以及哪些测试通过。

他们还具有在每次测试之前设置您在每个测试中需要的通用代码以及在所有测试完成后将其拆解的功能。

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

来源
Translate

我认为您不了解的是,像NUnit之类的单元测试框架将为您提供帮助。自动化中小型测试。通常,您可以在GUI中运行测试(NUnit(例如),只需单击一个按钮,然后-希望-看到进度条保持绿色。如果变成红色,则框架会向您显示哪个测试失败以及到底是什么错误。在正常的单元测试中,您经常使用断言,例如Assert.AreEqual(expectedValue, actualValue, "some description")-因此,如果两个值不相等,您将看到一条错误消息:“某些描述:预期的<expectedValue>,但为<actualValue>”。

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

来源
Translate

采用证词。您只需要知道就可以了:)

来源
Translate

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

单位, NUnit, mbUnit等是可以帮助您编写测试的工具。

来源
Translate

测试驱动开发已经取代了术语“单元测试”。作为旧计时器,我将提到它的更通用的定义。

单元测试还意味着测试大型系统中的单个组件。该单个组件可以是dll,exe,类库等。它甚至可以是多系统应用程序中的单个系统。因此,最终,单元测试最终将成为您要调用的大型系统中的任何一个的测试。

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

来源
Translate

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

来源
Translate

我在FoxForward 2007上参加了有关单元测试的演示,并被告知切勿对任何适用于数据的内容进行单元测试。毕竟,如果您对实时数据进行测试,则结果是不可预测的;如果您不对实时数据进行测试,则实际上并没有对所编写的代码进行测试。不幸的是,这是我最近做的大部分编码。 :-)

最近,我在编写保存和恢复设置的例程时确实在TDD上拍过照片。首先,我确认可以创建存储对象。然后,它具有我需要调用的方法。然后,我可以称之为。然后,我可以传递参数。然后,我可以为其传递特定的参数。依此类推,直到我最终确认它可以保存指定的设置,然后允许我更改它,然后再使用几种不同的语法恢复它。

我没有走到尽头,因为我需要立即执行常规操作,但这是一个很好的练习。

来源
Translate

如果收到一堆废话,并且似乎陷入了永久性的清理状态,那么您该怎么办?您知道,添加任何新功能或代码都会破坏当前的清理状态,因为当前的软件就像一间屋子。牌?

那我们该如何进行单元测试?

你从小开始。我刚进入的项目直到几个月前才进行过单元测试。如果覆盖率很低,我们只需选择一个没有覆盖率的文件,然后单击“添加测试”。

目前,我们的比例已超过40%,而且我们已经设法摘下了大多数低挂的水果。

(最好的部分是,即使覆盖率很低,我们也已经遇到了很多代码实例在做错事,而测试却抓住了它。这是促使人们添加更多测试的巨大动力。)

来源
Translate

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


下面的3个视频涵盖了使用javascript进行单元测试的过程,但是一般原则适用于大多数语言。

单元测试:分钟现在可以节省数小时-埃里克·曼-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负责其余的工作,而无需在更改时手动检查所有代码是否仍在工作您的代码。

另外,如果您不想对代码进行单元测试,但随着引入错误的机会增加,项目/代码库开始变得更大时,它会有所回报。

来源
aap
Translate

通常,单元测试和TDD使您可以缩短有关所编写软件的反馈周期。您无需在实现的最后阶段进行大型测试,而可以逐步测试所编写的所有内容。如您立即看到的那样,这可以极大地提高代码质量,在这些地方您可能会遇到错误。

来源
下一个问题:
.net -Subsonic Vs NHibernate