1.5.4 单元测试
在现代软件开发过程中,测试不再作为一个独立的生命周期。单元测试成为与编写代码同步进行的开发活动。单元测试能够提高程序员对程序的信心,保证程序的质量,加快软件开发速度,使程序易于维护。
1.单元测试概述
单元测试是在软件开发过程中要进行的最低级别的测试活动。在单元测试活动中,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。
在一种传统的结构化编程语言中,如C语言,要进行测试的单元一般是函数或子过程。在像C++这样的面向对象的语言中,要进行测试的基本单元是类。单元测试不仅仅是作为无错编码一种辅助手段在一次性的开发过程中使用,单元测试必须是可重复的,无论是在软件修改,或是移植到新的运行环境的过程中。因此,所有的测试都必须在整个软件系统的生命周期中进行维护。
经常与单元测试联系起来的另外一些开发活动包括代码走读(Code Review),静态分析(Static Analysis)和动态分析(Dynamic Analysis)。静态分析就是对软件的源代码进行研读,查找错误或收集一些度量数据,并不需要对代码进行编译和执行。动态分析就是通过观察软件运行时的动作,来提供执行跟踪、时间分析,以及测试覆盖度方面的信息。
2.单元测试的优点
þ 一种验证行为
程序中的每一项功能都是通过测试来验证它的正确性。它为以后的开发提供支援。就算是开发后期,我们也可以轻松地增加功能或更改程序结构,而不用担心这个过程中会破坏重要的东西,而且它为代码的重构提供了保障。这样,我们就可以更自由地对程序进行改进。
þ 一种设计行为
编写单元测试将使我们从调用者的角度观察、思考。特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。
þ 一种编写文档的行为
单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。
þ 具有回归性
自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地地快速运行测试。
3.越到项目后期,单元测试为何越难进行
在很多项目的初期,项目中的大部分程序员都能够自觉地去编写单元测试。随着项目的进展、任务的加重,离交付时间越来越近,不能按时完成项目的风险越来越大,单元测试就往往成为牺牲品了。项目经理因为进度的压力也不重视了,程序员也因为编码的压力和无人看管而不再为代码编写单元测试了。笔者亲身经历的项目都或多或少地发生过类似这样的事情。越是在项目的后期,能坚持编写单元测试的程序在整个项目组中所占的项目比例越低。
为了追赶项目进度,多数程序员将没有经过任何测试的程序代码上传到版本控制系统,项目经理也不再追问,照单全收。这样做的结果就是在项目后期,技术骨干人员只好加班加点进行系统集成。集成完了之后,下发给测试人员测试时,Bug的报告数量翻倍增长。程序员开始修改Bug,但还有非常多的Bug隐藏得很深,一直潜伏到生产环境去。
总之,在现代软件开发过程中,测试不再作为一个独立的生命周期,单元测试成为与编写代码同步进行的开发活动。单元测试能够提高程序员对程序的信心,保证程序的质量,加快软件开发速度,使程序易于维护。没有单元测试是绝对不行的。
4.NUnit单元测试工具的介绍与使用
(1)NUnit使用前介绍
NUnit是一个单元测试框架,专门针对测试.NET开发的程序,同类产品还包括JUnit(Java)、CPPUnit(C++),都属于xUnit中的成员。NUnit是xUnit家族中的第4个主打产品,完全由C#语言来编写,目前NUnit的最新版本是NUnit 2.4.3,可以到http://www.nunit.org/网站下载。
下面正式讲解Nunit。在讲解之前先来看一下单元测试的运行效果,如图1.28和图1.29所示。
图1.28 单元测试通过效果
图1.29 单元测试失败效果
在图1.28和图1.29中非常容易发现不同颜色的状态条,图1.28中是绿色的,图1.29中是红色的。如果所有测试案例运行成功,就为绿色;反之,如果有一个不成功,则为红色。
在右边面板的中间,可以看到测试进度条。进度条的颜色反映了测试执行的状态:
þ 绿色:描述目前所执行的测试都通过。
þ 黄色:意味某些测试忽略,但是这里没有失败。
þ 红色:表示有失败。
(2)使用NUnit进行单元测试
下面开始按步骤讲解如何在.NET中使用NUint工具。
①为单元测试代码创建一个Visual Studio 2005类库项目,将其命名为NUNIT,如图1.30所示。
图1.30 创建类库
②增加一个NUnit框架引用。在创建NUNIT项目中需要增加一个NUnit.framework.dll引用。首先在菜单栏选择“项目”/“添加引用”命令,弹出“添加引用”对话框,如图1.31所示。然后在安装的NUnit 2.4.3单元测试工具的目录下(安装所在盘:\Program Files\NUnit 2.4.3\bin)找到nunit.framework.dll文件,单击“确定”按钮,即可引用到项目中。
③在创建的类库中,首先引用命名空间NUnit.Framework,然后创建netTest类,并实现TestA方法和TestB方法。其中,TestFixture属性和Test属性,均属于NUnit.Framework的元素,分别用于指定要测试的类和测试的方法。
图1.31 添加nunit.framework.dll引用
完整代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
namespace NUNIT
{
[TestFixture]
public class netTest
{
[Test]
public void TestA()
{
int d, i;
for (i = 0; i < 10; i++)
{
d = i;
}
Assert.AreEqual(10, i); //判断的预期值是否为10
}
[Test]
public void TestB()
{
int d, i;
for (i = 0; i < 10; i++)
{
d = i;
}
Assert.AreEqual(11, i); //判断的预期值是否为11
}
}
}
④运行程序,将项目编译成DLL类库。
⑤运行NUnit GUI单元测试工具,打开编译的DLL文件,按F5键,根据进度条中的颜色,即可判断单元测试的成功与失败,如图1.32所示,TestA方法测试成功,TestB方法测试失败。
图1.32 单元测试结果