一、简介 NUnit是一款堪与JUnit齐名的开源的回归测试框架,供.net开发人员做单元测试之用,可以从www.nunit.org网站上免费获得,最新版本2.2.6。NUnit 2.2.6有5个下载文件,这里用的是NUnit-2.2.6-net-1.1.msi。下载后双击该文件,然后按提示进行安装,这样系统中就具备NUnit环境了。 二、配置类库 这次我选择的IDE是Borland的Delphi 2006(正确的叫法应该是Borland Developer Studio 2006,以下简称Delphi)。打开后点击菜单“File”->“New”->“Other”,打开“New Items”对话框:
在该对话框中,选择“C# Projects”或“Delphi for .NET Projects”,虽然两者在操作上会稍有差异,但其实相差并不很大。然后选择其中的“Console Application”,点击“OK”按钮。如果选择的是C#,那么会弹出一个“New Application”对话框:
请在其中设置项目名称和保存位置,我的项目名称为NUnitCS,位置为本机的G:\MDZPCK\Borland\MySY\NUnitCS,设置好后,点击“OK”按钮。如果选择的是Delphi,那么跟以前版本的Delphi一样,项目会直接被创建,而不弹出任何对话框。此时请按下快捷键Ctrl + S,打开Save对话框,对项目进行保存,这是一个良好的习惯。我将自己的项目文件名称设为NUnitOP.bdsproj(因为Delphi使用的是Object Pascal语言嘛),该文件名就是项目名称,保存路径为G:\MDZPCK\Borland\MySY\NUnitOP。 项目创建后,点击菜单“Project”->“Add Reference”,打开“Add Reference”对话框:
在“.NET Assembles”选项卡中找到组件名称为nunit.framework的一项,双击添加到“New References”中,别的组件不用管,然后点击“OK”按钮,此时在项目中就可以使用NUnit类库了。 三、编写用于测试的类 用于测试的类很简单,名为Book,只有id和name两个属性,这两个属性将分别用于两个用例当中。 下面开始编写,请点击菜单“File”->“New”->“Other”,打开“New Items”对话框:
在该对话框中选择“C# Projects”或“Delphi for .NET Projects”下的“New Files”,然后选中“Class”,点击“OK”按钮。此时Class文件虽然在工程中已生成,但尚未保存在硬盘上,所以请先按下快捷键Ctrl + S,我将文件命名为Book.cs和Book.pas。这里插一句,我感觉Delphi在文件保存这方面做的很差劲,如果没有经常保存文件的习惯,搞不好真的会出问题。 类创建后,需要修改代码,下边是C#代码: using System;
namespace NUnitCS { /// <summary> /// Summary description for Book. /// </summary> public class Book { private string pid = null; private string pname = null;
public string id { get { return pid; }
set { pid = value; } }
public string name { get { return pname; }
set { pname = value; } } } } 没什么可说的吧?下边是Delphi代码: unit Book;
interface
type TBook = class private pid : string; pname : string;
function GetId(): string; procedure SetId(value: string);
function GetName(): string; procedure SetName(value: string); public constructor Create; property id : string read GetId write SetId; property name : string read GetName write SetName; end;
implementation
constructor TBook.Create; begin inherited Create; end;
function TBook.GetId(): string; begin GetId := pid; end; procedure TBook.SetId(value: string); begin pid := value; end;
function TBook.GetName(): string; begin GetName := pname; end; procedure TBook.SetName(value: string); begin pname := value; end; end. 可以看到,和以前版本的Delphi代码相差不多,都是固定格式。这里可能引起费解的有两点:一个是属性,在Delphi中定义属性必须先为这个属性声明一个作为get访问器的函数和一个作为set访问器的过程,并实现之,然后使用property语句来定义属性,并将get访问器和set访问器与这两个函数和过程相关联。注意,这里建议将函数和过程声明在private部分,这样在调用时,就会只看到属性,而不会看到这两个函数和过程了。另一个费解的问题是,Book是类型还是命名空间。其实Book是命名空间,TBook才是类型,这种情况与Delphi文件的格式有关。在Delphi中,每建立一个文件都会相应建立一个命名空间,如果想让多个类在一个命名空间下,就需要把这几个类建在一个文件中,但这不符合Delphi的编码风格。最后,别忘了定义一个构造函数,Delphi是不会默认提供的。 至此,用于测试的类编写完成了。 四、编写测试用例 这里只用了一个类进行测试,名为BookTest,以前这样的类可能需要继承NUnit.Framework.TestCase类,但现在只需要对该类使用TestFixture属性进行标识即可,而无须继承了。BookTest类包含两个用例,分别对应该类的testId和testName方法,即每个方法实现了一个测试用例。注意,在NUnit中,这些用来实现测试用例的方法有两种手段进行标识:一个是以testXXX的格式来命名,一个是使用Test属性进行标识。此外,BookTest还有Init和Dispose这两个方法,并分别使用SetUp和TearDown属性来进行标识,前者在每个测试方法开始之前执行,多用来做初始化;后者在每个测试方法完成之后执行,多用来清理资源。注意,这两个方法的名称并没有什么限制,但必须用SetUp和TearDown属性进行标识。另外,NUnit还提供了TestFixtureSetUp和TestFixtureTearDown属性,功能与SetUp和TearDown类似,但前者是在所有用例执行之前做初始化、之后做清理,而后者是在每个用例执行之前做初始化、之后做清理。下面开始编写BookTest。 点击菜单“File”->“New”->“Other”,打开“New Items”对话框,在该对话框中选择“C# Projects”或“Delphi for .NET Projects”下的“New Files”,然后选中“Class”,点击“OK”按钮。此时请按下快捷键Ctrl + S,保存文件,我将文件命名为BookTest.cs和BookTest.pas。下面修改代码,C#代码如下: using System; using NUnit.Framework;
namespace NUnitCS { /// <summary> /// Summary description for Class1. /// </summary> [TestFixture] public class BookTest { Book book = null;
[TestFixtureSetUp] public void Init() { Console.WriteLine("测试开始!"); book = new Book(); Console.WriteLine("book对象被初始化!"); }
[Test] public void testId() { book.id = "001"; //设置id属性的值为001 //使用Assert查看id属性的值是否为001 Assert.AreEqual("001", book.id); Console.WriteLine("id属性被测试!"); }
[Test] public void testName() { book.name = "ASP"; //设置name属性的值为ASP //使用Assert查看name属性的值是否为JSP,这是个必然出现错误的测试 Assert.AreEqual("JSP", book.name); Console.WriteLine("name属性被测试!"); }
[TestFixtureTearDown] public void Dispose() { Console.WriteLine("book对象将被清理!"); book = null; Console.WriteLine("测试结束!"); } } } 这里Init和Dispose方法没什么好说的,就是执行了对book对象的初始化和清理,不过testId和testName需要说明一下。前者是在对book的id属性进行测试,首先赋值为”001”,然后使用Assert的AreEqual方法查看id属性中存放的值是否是期待的值,由于我的期待值也是”001”,所以执行后这个用例应该是成功的;后者则是对book的name属性进行测试,也是首先赋值为”ASP”,然后使用Assert的AreEqual方法查看其值是否是期待的,由于我特意将期待值设定为根本不可能的”JSP”,因此这个用例执行后会出现一个错误。但请注意,由于我是特意要让测试出现错误,所以将期待值设定成了不可能的值,如果你是测试人员,请千万不要这么做,否则如果别的地方导致了错误,很容易给自己造成不必要的麻烦。 下面简单介绍一下上边用到的静态类NUnit.Framework.Assert。该类主要包含20个方法: 1.AreEqual()和AreNotEqual()方法,用来查看两个对象的值是否相等或不等,与对象比较中使用的Equals()方法类似。 2.AreSame()和AreNotSame()方法,用来比较两个对象的引用是否相等或不等,类似于通过“Is”或“==”比较两个对象。 3.Contains()方法,用来查看对象是否在集合中,集合类型应与System.Collections.IList兼容。示例: object o = new object(); ArrayList al = new ArrayList(); al.Add(o); Assert.Contains(o, al); 4.Greater()和Less()方法,用来比较两个数值的大小,前者相当于大于号(>),后者相当于小于号(<)。 5.IsInstanceOfType()和IsNotInstanceOfType()方法,用来判断对象是否兼容于指定类型。示例: Type t = new object().GetType(); string s = ""; Assert.IsInstanceOfType(t, s); 由于Object是.net中所有类型的基类,String类型兼容于Object,因此这个示例是能够运行通过的。而下边这个示例运行将是失败的: Type t = new ArrayList().GetType(); string s = ""; Assert.IsInstanceOfType(t, s); 6.IsAssignableFrom()和IsNotAssignableFrom()方法,用来判断对象是否是指定类型的实例。示例: Type t = new object().GetType(); string s = ""; Assert.IsAssignableFrom(t, s); 这个示例与之前的示例是一样的,但由于字符串s不是Object类型的,因此无法运行通过。而下边这个实例可以运行通过: Type t = new string("").GetType(); string s = ""; Assert.IsAssignableFrom(t, s); 7.IsFalse()和IsTrue()方法,用来查看变量是是否为false或true,如果IsFalse()查看的变量的值是false则测试成功,如果是true则失败,IsTrue()与之相反。 8.IsNull()和IsNotNull()方法,用来查看对象是否为空和不为空。 9.IsEmpty()和IsNotEmpty()方法,用来判断字符串或集合是否为空串或没有元素,其中集合类型应与ICollection兼容。 10.IsNaN()方法,用来判断指定的值是否不是数字。 11.Fail()方法,意为失败,用来抛出错误。我个人认为有两个用途:首先是在测试驱动开发中,由于测试用例都是在被测试的类之前编写,而写成时又不清楚其正确与否,此时就可以使用Fail方法抛出错误进行模拟;其次是抛出意外的错误,比如要测试的内容是从数据库中读取的数据是否正确,而导致错误的原因却是数据库连接失败。 12.Ignore()方法,意为忽略,用来忽略后续代码的执行,用途可以参考Fail()方法。 此外,NUnit还提供了一个专用于字符串的静态类NUnit.Framework. StringAssert,该类主要包含4个方法: 1.Contains()方法,用来查看指定的第二个字符串中是否包含了第一个字符串。 2.StartsWith ()和EndsWith ()方法,分别用来查看指定的第一个字符串是否位于第二个字符串的开头和结尾。 3.AreEqualIgnoringCase()方法,用来比较两个字符串是否相等。 下面再看一下Delphi代码: unit BookTest;
interface
uses Book, NUnit.Framework;
type [TestFixture] TBookTest = class book : TBook; private { Private Declarations } public constructor Create; [TestFixtureSetUp] procedure Init(); [Test] procedure testId(); [Test] procedure testName(); [TestFixtureTearDown] procedure Dispose(); end;
implementation
constructor TBookTest.Create(); begin inherited Create; end;
procedure TBookTest.Init(); begin onsole.WriteLine(''''测试开始!''''); book := TBook.Create(); Console.WriteLine(''''book对象被初始化!''''); end;
procedure TBookTest.testId(); begin book.id := ''''001''''; //设置id属性的值为001 //使用Assert查看id属性的值是否为001 Assert.AreEqual(''''001'''', book.id); Console.WriteLine(''''id属性被测试!''''); end;
procedure TBookTest.tes [1] [2] 下一页 [系统软件]InstallShield Express for delphi制作安装程序定… [常用软件]InstallShield Express制作Delphi数据库安装程序 [Delphi程序]为什么选择Delphi.Net ? [Delphi程序]《关于VisiBroker For Delphi的使用》(4) [Delphi程序]Delphi 程序员代码编写标准指南 [Delphi程序]转贴:Conversion to Delphi 6: Missing unit Pro… [Delphi程序]Borland Delphi 9 的新特性 [Delphi程序]Delphi 键盘码表 [Delphi程序]Chuck Jazdzewski的离开意味着Delphi的终结吗? [Delphi程序]Delphi Access violations 问题的解决之道
|