我如何真正单元测试代码?

时间:2010-07-11 06:29:05

标签: unit-testing

我正在阅读Joel Test 2010,这让我想起了我在单元测试中遇到的问题。

我如何真正进行单元测试?我没有单元测试功能?只有全班?如果我有15个类<20行怎么办?我是否应该为每个类别编写一个35行单元测试,将15 * 20行写入15 *(20 + 35)行(从300到825,将近3倍的代码)。

如果一个类只被模块中的其他两个类使用,我应该对它进行单元测试,还是对其他两个类的测试是否足够?如果他们都是&lt;我应该打扰30行代码吗?

如果我编写代码来转储数据,我就不需要阅读它,例如使用另一个应用程序。另一个应用程序不是命令行,或者它无法验证数据是否良好。我还需要进行单元测试吗?

如果应用程序是实用程序且总数小于500行代码,该怎么办?或者在那一周使用并将在未来使用,但总是需要重新配置,因为它用于快速批处理,每个项目都需要调整,因为期望输出不变。 (我试图说没有办法解决它,因为有效的原因它总会被调整)我是否对它进行单元测试,如果是这样的话? (也许我们不关心我们是否打破了过去使用过的功能,但现在或将来都没有。)

我认为这应该是一个维基。也许人们想说出他们应该单位测试(或不应该)的确切内容?也许书籍链接很好。我尝试了一个,但它从未澄清应该进行单元测试的内容,只是编写单元测试和解决方案的问题。


此外,如果类只是在该项目中(通过设计,规范或其他原因)并且该类不是单独使用(假设它使用返回html准备好的注释的数据生成html)我真的需要测试一下吗?通过检查当我的项目没有使用空注释时,所有公共函数是否允许空注释对象。它的那些东西让我想知道我是否在测试错误的代码。在项目中还有大量的课程。它是边界线一次性或不是非常有用的单独代码困扰我。

12 个答案:

答案 0 :(得分:25)

这就是我所听到的,无论你是否以这种方式表达:一连串的问题和借口,为什么单元测试可能不适用于你的代码。换句话说:“我看不出我将从单元测试中得到什么,而且他们写的很麻烦;也许他们不适合我?”

你知道吗?你或许是正确的。单元测试不是灵丹妙药。单元测试无法涵盖大量广泛的测试。

但是,我认为,你错误地估计了维护成本,以及代码中可能出现的问题。所以这是我的想法:

  • 我应该测试小班吗?是的,如果该班级中有些东西可能会破坏。
  • 我应该测试功能吗?是的,如果此功能中有些东西可能会破坏。你为什么不呢?或者您是否关注它是否被视为一个单位?这只是对名称的争论,不应该对你是否应该为它编写单元测试有任何影响!但是,根据我的经验,将方法或功能描述为被测单元是很常见的。
  • 如果一个类被其他两个类使用,我应该对它进行单元测试吗?是的,如果有什么可能在该类中断。 我应该单独测试吗?这样做的好处是能够将断点直接隔离到共享类,而不是通过使用类来查看它们是否已损坏或其中一个他们的依赖。
  • 如果其他程序会读取它,我应该测试我班级的数据输出吗? Hell yes ,特别是如果其他程序是第三方程序的话!这是单元测试的一个很好的应用(或者可能是系统测试,取决于测试中涉及的隔离):向您自己证明您输出的数据正是您认为应该输出的数据。我想你会发现它有能力无法简化支持调用。 (但请注意,它不能代替客户端的良好验收测试。)
  • 我应该测试一次性代码吗?可能。追求TDD策略会更快地将您的一次性代码推出门吗?它可能。具有可以适应新约束的经过单元测试的可靠块,是否会减少抛出代码的需要?或许。
  • 我应该测试不断变化的代码吗?是的。只需确保所有适用的测试都是最新的并通过!毕竟,不断变化的代码特别容易出错,并且实现安全更改是单元测试的另一个好处。此外,它可能会给您的不变代码带来尽可能强大的负担,以实现这种变化速度。并且你知道如何让自己说服一段代码是否健壮......
  • 我应该测试不再需要的功能吗?不,您可以删除测试,也可能删除代码(测试以确保您在此过程中没有破坏任何内容,当然!)。不要让单元测试腐烂,特别是如果测试不再起作用或运行,或者组织中的人员将远离单元测试并且您将失去优势。我看到过这种情况。它不漂亮。
  • 我是否应该测试我的项目未使用的代码,即使它是在我的项目上下文中编写的?取决于项目的可交付成果是什么,以及优先级是什么你的项目是。但是你确定项目之外没有人会使用它吗?如果他们不这样做,而你却不是,也许这只是死代码,在这种情况下见上文。从我的角度来看,如果我的测试没有涵盖所有重要功能,项目是否使用了所有功能,我觉得我没有完成一个完整的课程。我喜欢那些感觉完整的课程,但我一直关注不要过度设计一些我不需要的东西。如果我把一些东西放在一个类中,那么,我打算使用它,因此我想确保它有效。这是个人品质和满意度的问题。

答案 1 :(得分:17)

不要注意计算代码行。编写尽可能多的测试代码,以说服自己每个关键功能都经过全面测试。作为一个极端的例子,SQLite项目有一个测试:源代码比率超过600:1。我在这里使用了“极端”一词;正在进行的大量测试可能是SQLite占据全球的主要原因。

答案 2 :(得分:4)

你怎么能做所有这些计算?理想情况下,您永远不应该处于这样的情况:您可以计算已完成的类的行,然后从头开始编写单元测试。这两种类型的代码(实际代码和测试代码)应该一起开发和发展,唯一真正让你担心的LOC指标是测试代码的0 LOC。

答案 3 :(得分:2)

代码和测试的相对LOC计数毫无意义。更重要的是测试覆盖率。最重要的是发现错误。

当我编写单元测试时,我倾向于集中精力测试更可能包含错误的复杂代码。简单的东西(例如简单的getter和setter方法)不太可能包含bug,并且可以通过更高级别的单元测试间接测试。

答案 4 :(得分:2)

前段时间,我您记得的同一个问题。我研究了很多文章,教程,书籍等等......尽管这些资源给了我一个很好的起点,但我仍然对如何有效地应用单元测试代码感到不安全。在遇到xUnit Test Patterns: Refactoring Test Code并将其放入我的架子大约一年后(你知道,我们有很多东西要研究),它给了我所需要的有效应用单元测试代码。有了很多有用的模式(和建议),您将看到如何成为单元测试编码器。主题为

  • 测试策略模式
  • 基本模式
  • 灯具设置模式
  • 结果验证模式
  • 测试双重模式
  • 测试组织模式
  • 数据库模式
  • 价值模式

等等......

我会告诉你,例如,派生价值模式

  

当我们需要测试将复杂对象作为参数的方法时,通常会使用派生输入。例如,彻底的输入验证测试要求我们使用对象集的每个属性对一个或多个可能的无效值执行该方法。因为第一个被拒绝的值可能会导致方法的终止我们必须在单独的调用中验证每个错误的属性。我们可以通过首先创建一个有效对象,然后用一个无效值替换其中一个属性来轻松地实例化无效对象

与您的问题相关的测试组织模式(Testcase类每个功能

  

随着测试方法数量的增加,我们需要决定在哪个Testcase类中放置每个Test方法...使用Testcase类每个功能为我们提供了一个系统的方法打破将一个大型的Testcase类分成几个较小的而无需更改测试方法。

但在阅读之前

xUnit Test Patterns http://xunitpatterns.com/Cover-Small.gif

我的建议:仔细阅读

答案 5 :(得分:1)

您似乎担心可能会有比测试中的代码更多的测试代码。

我认为比率可能比你说的要高。我希望任何严肃的测试都可以进行广泛的投入。所以你的20行类可能有200行测试代码。

我不认为这是一个问题。对我来说有趣的是,编写测试似乎并没有减慢我的速度。相反,它让我在编写代码时专注于代码。

所以,是的,测试一切。尽量不要将测试视为一件苦差事。

答案 6 :(得分:1)

我是一个团队的成员,他们刚刚开始在我们现有的,相当古老的代码库中添加测试代码 我在这里使用'test'是因为我觉得它可能非常模糊,因为它是一个单元测试,系统测试,或集成测试,或其他什么。这些术语之间的差异具有较大的灰色区域,并且不会增加很多价值。

因为我们生活在现实世界中,所以我们没有时间为所有现有功能添加测试代码。我们仍然有测试人员Dave,他发现了大多数错误。相反,在我们开发时,我们编写测试。你知道如何在你告诉老板它运作之前运行你的代码吗?好吧,使用单位框架(我们使用Junit)来完成这些运行。只需保留所有内容,而不是删除它们。无论你通常做什么来说服自己它是有效的。那样做。

如果编写代码很容易,那就去做吧。如果没有,请将它留给戴夫,直到你想到一个好的方法来实现自动化,或者直到你在“他们”试图决定将什么放入下一个版本的项目之间获得那个空闲时间。

答案 7 :(得分:1)

对于java你可以使用junit

JUnit的

JUnit是一个编写可重复测试的简单框架。它是单元测试框架的xUnit体系结构的一个实例。

* Getting Started
* Documentation
* JUnit related sites/projects
* Mailing Lists
* Get Involved

入门 要开始进行单元测试和JUnit,请阅读文章:JUnit Cookbook。 本文介绍使用JUnit 4进行的基本测试编写。

您可以在org.junit.samples包中找到其他示例:

* SimpleTest.java - some simple test cases
* VectorTest.java - test cases for java.util.Vector

JUnit 4.x只附带一个文本TestRunner。对于图形反馈,大多数主要IDE都支持JUnit 4.如果需要,可以通过向每个测试类添加以下方法在JUnit 3环境中运行JUnit 4测试:

public static Test suite(){    返回新的JUnit4TestAdapter(ThisClass.class); }

文档

JUnit Cookbook
    A cookbook for implementing tests with JUnit.
Javadoc
    API documentation generated with javadoc.
Frequently asked questions
    Some frequently asked questions about using JUnit.
Release notes
    Latest JUnit release notes
License
    The terms of the common public license used for JUnit.

以下文档仍然描述了JUnit 3.8。

The JUnit 3.8 version of this homepage
Test Infected - Programmers Love Writing Tests
    An article demonstrating the development process with JUnit.
JUnit - A cooks tour 

JUnit相关项目/网站

* junit.org - a site for software developers using JUnit. It provides instructions for how to integrate JUnit with development tools like JBuilder and VisualAge/Java. As well as articles about and extensions to JUnit.
* XProgramming.com - various implementations of the xUnit testing framework architecture. 

邮件列表 有三个junit邮件列表:

* JUnit announce: junit-announce@lists.sourceforge.net Archives/Subscribe/Unsubscribe
* JUnit users list: junit@yahoogroups.com Archives/Subscribe/Unsubscribe
* JUnit developer list: junit-devel@lists.sourceforge.net Archives/Subscribe/Unsubscribe

参与进来 JUnit庆祝程序员测试他们自己的软件。因此,包含JUnit TestCase的bug,补丁和功能请求比没有JUnit TestCases的错误,补丁和功能请求更有可能被解决。 JUnit源代码现在托管在GitHub上。

答案 8 :(得分:1)

一种可能性是将“测试代码”缩减为描述测试的语言,并使用解释器来运行测试。我参与过的团队已经将这一点用于了很好的目的,这使得我们可以编写比“代码行”更多的测试。

这使我们的测试编写得更快大大提高了测试的易读性。

答案 9 :(得分:0)

我将回答我认为是你问题的要点。首先,你应该写多少测试代码?那么,Test-Driven Development在这里可以提供一些帮助。我没有像理论上提出的那样严格使用它,但我发现首先编写测试通常可以帮助我更好地理解我想要解决的问题。此外,它通常会带来良好的测试覆盖率。

其次,您应该测试哪些课程?同样,TDD(或更确切地说是其背后的一些原则)可以提供帮助。如果您开发系统top down并首先编写测试,那么在编写内部类时,您将对外部类进行测试。如果内部类有错误,这些测试应该失败。

TDD也与Design for Testability的想法紧密结合。

我的回答并非旨在解决您的所有问题,而是为您提供一些想法。

答案 10 :(得分:0)

我认为不可能写一份关于你应该和不应该进行单元测试的全面指南。对象,类和函数的排列和类型太多,无法涵盖所有​​这些。

我建议将个人责任应用于测试,并自行确定答案。这是你的代码,你负责它的工作。如果它破裂,你必须支付修复代码,修复数据,承担收入损失的责任,并向他们试图使用它时应用程序破坏的人道歉。底线 - 您的代码永远不会破坏。那么你需要做些什么才能确保这一点?

有时,单元测试可以很好地帮助您测试库中的所有特定方法。有时单元测试只是繁忙工作,因为您可以根据在更高级别测试期间使用代码来判断代码是否正常工作。你是开发人员,你有责任确保代码永远不会破坏 - 你认为最好的方法是什么?

如果您认为在特定情况下进行单元测试是浪费时间 - 可能是。如果您已经在所有应用程序用例场景中测试了代码并且它们都可以正常工作,则代码可能很好。

如果您不理解的代码中发生了任何事情 - 即使最终结果是可接受的 - 那么您需要进行更多测试以确保没有任何您不理解的内容。

对我来说,这似乎是常识。

答案 11 :(得分:0)

单元测试主要用于从功能方面测试您的单元。您可以测试并查看是否有特定输入,我们是否会收到预期值,还是会抛出正确的异常?

单元测试非常有用。我建议你写下这些测试。但是,并非所有东西都需要进行测试。例如,您不需要测试简单的getter和setter。

如果您想通过Eclipse用Java编写单元测试,请查看“How To Write Java Unit Tests”。我希望它有所帮助。