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

是什么? 它对我有什么用? 我为什么要用它? 什么时候用(什么时候不用)? 有哪些常见的陷阱和误解


当前回答

我在大学里从未学过单元测试,我花了一段时间才“学会”它。我读到它,心想“啊,对,自动化测试,我想那应该很酷”,然后我就忘记了。

It took quite a bit longer before I really figured out the point: Let's say you're working on a large system and you write a small module. It compiles, you put it through its paces, it works great, you move on to the next task. Nine months down the line and two versions later someone else makes a change to some seemingly unrelated part of the program, and it breaks the module. Worse, they test their changes, and their code works, but they don't test your module; hell, they may not even know your module exists.

现在你有了一个问题:坏代码在主干中,甚至没有人知道。最好的情况是内部测试人员在您发布之前就发现了它,但是在游戏后期修复代码的成本很高。如果没有内部测试人员发现它……嗯,这确实会非常昂贵。

The solution is unit tests. They'll catch problems when you write code - which is fine - but you could have done that by hand. The real payoff is that they'll catch problems nine months down the line when you're now working on a completely different project, but a summer intern thinks it'll look tidier if those parameters were in alphabetical order - and then the unit test you wrote way back fails, and someone throws things at the intern until he changes the parameter order back. That's the "why" of unit tests. :-)

其他回答

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

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

如果你想使用Kent Beck推广的TDD方法开发项目,像NUnit、xUnit或JUnit这样的库是必须的:

你可以阅读《测试驱动开发介绍》(TDD)或Kent Beck的《测试驱动开发:举例说明》。

然后,如果你想确保你的测试覆盖了代码中“好的”部分,你可以使用NCover、JCover、PartCover或其他软件。它们会告诉你代码的覆盖率。取决于你对TDD的熟练程度,你会知道你是否已经很好地练习了它:)

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

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

但是,如果您可以在任何时间运行您的测试,只需单击一下,以完全相同的方式,在几秒钟内,那么一旦有什么东西坏了,它们就会立即显示给您。如果您还将单元测试集成到您的自动化构建过程中,即使在看似完全无关的更改破坏了代码库中遥远部分的某些情况下,它们也会提醒您错误——当您甚至不会想到需要重新测试特定的功能时。

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

unit tests shorten the development feedback loop dramatically: with a separate testing department it may take weeks for you to know that there is a bug in your code, by which time you have already forgotten much of the context, thus it may take you hours to find and fix the bug; OTOH with unit tests, the feedback cycle is measured in seconds, and the bug fix process is typically along the lines of an "oh sh*t, I forgot to check for that condition here" :-) unit tests effectively document (your understanding of) the behaviour of your code unit testing forces you to reevaluate your design choices, which results in simpler, cleaner design

反过来,单元测试框架使您更容易编写和运行测试。

首先,无论是谈论单元测试还是其他类型的自动化测试(集成、加载、UI测试等),与您所建议的关键区别在于它是自动化的、可重复的,并且不需要消耗任何人力资源(=没有人需要执行测试,它们通常按下按钮就可以运行)。

单元测试,粗略地说,就是在与测试代码隔离的情况下测试代码。我想到的直接优势是:

测试的运行变得自动化和可重复 您可以在更细粒度的级别上进行测试,而不是通过GUI进行点击测试

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

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

您不需要编写推测性的“我将来可能需要这个”代码——只要能够通过测试即可 您编写的代码总是会被测试覆盖 通过先编写测试,您不得不考虑如何调用代码,从长远来看,这通常会改善代码的设计。

如果你现在还没有做单元测试,我建议你现在就开始做。找一本好书,实际上任何xUnit-book都可以,因为它们之间的概念可以很好地转换。

有时编写单元测试会很痛苦。当出现这种情况时,试着找个人来帮助你,并抵制住“只写该死的代码”的诱惑。单元测试很像洗碗。这并不总是令人愉快的,但它让你的比喻厨房保持干净,而你真的希望它干净。:)


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