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