2010-02-23 112 views
7

基本上我有两个主要问题:如何进行单元测试?

  • 你究竟应该测试什么?
  • 你怎么做到的?

问题是我有几个应用程序依赖于数据库连接和/或通信应用程序,这意味着大多数测试用例都是集成测试(或者我认为)。

大多数类是本身非常简单,但是实现的通信协议,这是那些将是自动化测试有用的人,似乎可以很好地成为“单元测试”的模式。

另一个例子。我为消费者/生产者模式开发了带有多线程支持的I管道结构。当一个线程读取管道并发现它为空时,它会阻塞,直到写入者写入管道。我应该使用单元测试来测试这个类吗?

你如何决定单元测试?

编辑:我的意思是自动单元测试编写单元测试。

回答

4

你单元测试你的代码的单位。真正的问题是什么构成一个单位?

在面向对象的环境中,单元是一个类。一个类,因为一个对象的行为随着对象的状态而变化,所以单独测试一个方法不会得到最完整的结果。

首先你需要确定类的不变量。也就是说,对于班级的所有事例来说,这些事情总会是真的。例如。在Fraction类不变可能是分母!= 0

接下来,你需要确定每种方法的合同,也就是说,这些方法的前置和后置条件。

然后你为每个可能出现的情况编写测试。因此,对于单个课程,您最终可能会有许多测试方法来测试每种方法可能遇到的各种情况。在每次测试中,您都要确保该类的不变式保持不变,并且方法的合同永远不会中断。

在某些情况下,像您提供可能需要以测试你的类的条件,创造环境中的其他对象的例子。在这些情况下,你可以使用模拟对象。

+0

所以,即使你需要模拟其他对象或模拟外部事件或设备,它可以被认为是一个单元测试和测试应该写出来吗? – 2010-02-23 23:22:38

+0

@Jorge Corboda是的。我想是这样。很多像运行在容器中的代码一样的环境很难单独测试。所以为测试创建模拟对象被认为是很好的做法。尽管测试代码可以独立运行,这一点很重要。 – 2010-02-23 23:55:47

+0

虽然从技术上来说,任何在被测单元(数据库,文件系统等)之外具有依赖性的代码测试都是集成测试。但是,这两个术语可以交替使用,而且往往是相同的。 – ZombieSheep 2010-02-24 11:28:08

0

单元测试是测试整个单元的工作原理相同,因为它改变之前一样,在变化所做的改进。如果您正在更改一个模块的窗口,那么你测试模块。这与测试每个模块的系统测试相比。如果你的改变影响了很多模块(不知道你的系统是如何设置的),那么它应该得到一个系统测试。

+0

嗯,我的错,我的意思是自动单元测试...就像你实际编码的那个:) – 2010-02-23 23:20:29

1

您应该抽象的基础设施问题(即从数据库中检索数据的代码,代码,做文件I/O等),这样就可以存根/为了嘲笑那些部分单元测试你的应用。然后,您将能够针对您的基础架构代码编写针对性/特定的测试以进行测试。你会发现自己创建更多的接口(在你的应用程序中似乎创建),并需要使用更好的面向对象原则(即。SOLID)以开发更具可测试性的应用程序。

我是在同一条船上一年前,你在,而且一本书,真的帮了我通过它(与实践一些手一起)是The Art of Unit Testing by Roy Osherove

+0

我听说过有关这方面的好东西...... – RSolberg 2010-02-24 00:20:18

1

单元测试的测试单位(即方法或功能)隔离,在一个专门的,受控制的环境。每个单元测试通过仅实例化执行一个测试所需的类,将它们置于已知状态,然后调用要测试的方法并验证结果,在自己的环境中创建。该验证通过关于该方法的行为(与其实现相反)的断言完成。

对行为进行验证是非常重要的,因为这样可以在不中断单元测试的情况下修改实现,因此使用单元测试作为修改的安全网。

所有语言都有[至少]一个unit test framework,它们的作用是执行单元测试。有两种编写单元测试的方法:测试优先或最后测试。

测试优先也被称为Test-Driven Development。基本上,它需要三个步骤:

  1. 写一个失败的测试
  2. 写只是足够多的代码,使之通过
  3. 重构代码,把它清理干净(去除重复...)

TDD的支持者声称这导致了可测试的代码,但事实上可能很难编写单元测试,特别是当方法做了几件事时。建议遵循单一责任原则。

关于管结构和通信协议例如,一些指引说 a test is not a unit test if

  • 它谈论到数据库
  • 它通过网络
  • 通信倒是文件系统
  • ...

当某个线程读取管道并找到 时,它会清空该块,直到写入器 写入管道。我应该使用 单元测试来测试这个类吗?

我将测试的类,但不阻挡读方法,因为我相信它是从阻挡调用操作系统的功能read()建立。

+0

TDD有一个非常*重要的步骤4 - “确保重构后测试仍然通过”。显而易见,但有时被忽视。 – ZombieSheep 2010-02-24 11:29:03

+0

同意这很重要 - 但它是重构的一部分,而不是TDD。 TDD周期是“红色,绿色,重构”。 – philant 2010-02-24 13:54:38