NUnit2.0详细使用
方法
@H_
403_0@注:NUnit
中文文档可以参看我的另一个
站点:
http://www.36sign.com/nunit
@H_
403_0@
@H_
403_0@前一段时间,有人问我在.NET里如何进行TDD开发.这个问题促使我想对NUnit做一个详细的介绍.因为我们大家都知道NUnit是在.NET进行TDD的利器.
@H_
403_0@如果你已经知道很多关于NUnit的应用,请指出我的不对之处和提出一些建议,使本文更加完善.如果你对NUnit还不是很了解的话,我建议你还是阅读一下.
@H_
403_0@本文分为以下部分:
@H_
403_0@1.TDD的简介
@H_
403_0@首先什么是TDD呢?KentBeck在他的<<测试驱动开发>>(Addison-WesleyProfessional,2003)一书中,使用下面2个原则来定义TDD:
@H_
403_0@·除非你有一个失败的
自动测试,永远不要写一单行
代码.
@H_
403_0@·阻止重复
@H_
403_0@我想第一个原则是显而易见的.在没有失败的
自动测试下就不要写
代码.因为测试是嵌入在
代码必须满足的需求中.如果没有需求,就没有必要实现任何东西.所以这个原则阻止我们去实现那些没有测试和在
解决方案中不需要的
功能.
@H_
403_0@第二个原则说明了在一个程序中,不应该包含重复的
代码.如果
代码重复,我想这就是不好的软件设计的象征.随着时间的流逝,它会对程序造成不一致的问题,并且使
代码变非常混乱,因为我们时常不会记得重复
代码的位置.如果发现
代码重复,我想我们应该立即
删除代码重复.其实这就涉及到重构了.在这里我就不多讲了.
@H_
403_0@一般来说,测试分为2种类型,一是程序员自己的测试,另外一种是客户的测试.关于客户测试,我推荐一个FIT的框架,非常不错。在这里,我们讲的TDD就是程序员测试.那么什么是程序员测试呢?我认为就是我们常说的单元测试.既然是单元测试,在.NET里势必会用到某些工具,目前最著名恐怕就是我即将介绍的NUnit了,@H_
403_0@2.NUnit的介绍
@H_
403_0@NUnit是一个单元测试框架,专门针对于.NET来写的.其实在前面有JUnit(Java),CPPUnit(C++),他们都是xUnit的一员.最初,它是从JUnit而来.现在的版本是2.2.接下来我所用的都是基于这个版本.
@H_
403_0@NUnit最初是由JamesW.Newkirk,AlexeiA.Vorontsov和PhilipA.Craig,后来开发团队逐渐庞大起来.在开发过程中,KentBeck和ErichGamma2位牛人也提供了许多帮助.看来对于NUnit还真是下了一番力气了.J
@H_
403_0@NUnit是xUnit家族种的第4个主打产品,完全由C#语言来编写,并且编写时充分利用了许多.NET的特性,比如反射,客户
属性等等.
@H_
403_0@最重要的一点是它适合于所有.NET语言.
@H_
403_0@如果你还没有下载,可以到
http://www.nunit.org/去下载.
@H_
403_0@2.1NUnit的介绍
@H_
403_0@Ok,下面正式讲解NUnit.在讲解之前,看看几张
图片:
@H_
403_0@
@H_
403_0@图1NUnit运行的
效果
@H_
403_0@
@H_
403_0@图2NUnit运行的另外一个
效果
@H_
403_0@从中我们可以非常容易发现,右边是个状态条,图1是红色的,图2是绿色的.为什么会这样呢?因为如果所有测试案例运行成功,就为绿色,反之如果有一个不成功,则为红色,但也有黄色的.左面的工作域内则是我们写的每一个单元测试.
@H_
403_0@通过上面的
图片,我想你对NUnit有个总的了解了.
@H_
403_0@接下来还是分为2个部分,一是NUnit的布局,另外一部分就是它的核心概念.
@H_
403_0@首先熟悉一下NUnitGUI的布局.
@H_
403_0@让我们更进一步看一下测试运行器窗口的布局。在右边面板的中间,可以看到测试进度条。进度条的颜色反映了测试执行的状态:
@H_
403_0@
@H_
403_0@*绿色描述目前所执行的测试都通过
@H_
403_0@*黄色意味某些测试忽略,但是这里没有失败
@H_
403_0@*红色表示有失败
@H_
403_0@
@H_
403_0@
底部的状态条表示下面的状态:
@H_
403_0@
@H_
403_0@*状态.说明了现在运行测试的状态。当所有测试完成时,状态变为Completed.运行测试中,状态是Running:<test-name>(<test-name>是正在运行的测试
名称)。
@H_
403_0@*TestCases说明加载的程序集中测试案例的总个数。这也是测试树里叶子节点的个数。
@H_
403_0@*TestsRun已经完成的测试个数。
@H_
403_0@*Failures到目前为止,所有测试中失败的个数.
@H_
403_0@*Time
显示运行测试时间(以秒计)
@H_
403_0@
@H_
403_0@File主
菜单有以下
内容:
@H_
403_0@
@H_
403_0@*NewProject允许你创建一个新工程。工程是一个测试程序集的集合。这种机制让你组织多个测试程序集,并把他们作为一个组对待。
@H_
403_0@*Open加载一个新的测试程序集,或一个以前保存的NUnit工程
文件。
@H_
403_0@*Close
关闭现在加载的测试程序集或现在加载的NUnit工程。
@H_
403_0@*Save保存现在的Nunit工程到一个
文件。如果正工作单个程序集,本
菜单项允许你创建一个新的NUnit工程,并把它保存在
文件里。
@H_
403_0@*SaveAs允许你将现有NUnit工程作为一个
文件保存。
@H_
403_0@*Reload强制重载现有测试程序集或NUnit工程。NUnit-Gui
自动监测现加载的测试程序集的变化。
@H_
403_0@
@H_
403_0@当程序集变化时,测试运行器重新加载测试程序集。(当测试正运行时,现在加载的测试程序集不会重新加载。在测试运行之间测试程序集仅可以重新加载。一个忠告:如果测试程序集依赖另外一个程序集,测试运行器不会观察任何依赖的程序集。对测试运行器来说,强制一个重载使全部依赖的程序集变化可见。
@H_
403_0@
@H_
403_0@*RecentFiles说明5个最近在NUnit中加载的测试程序集或NUnit工程(这个列表在Windows
注册表,由每个
用户维护,因此如果你共享你的PC,你仅看到你的测试)。最近程序集的
数量可以使用Options
菜单项
修改,可以访问Tool主
菜单。
@H_
403_0@*Exit
退出。
@H_
403_0@*View
菜单有以下
内容:
@H_
403_0@*Expand一层层扩展现在树中所选节点
@H_
403_0@*Collapse折叠现在树中选择的节点
@H_
403_0@*ExpandAll递归扩展树中所选节点后的所有节点
@H_
403_0@*CollapseAll递归折叠树中所选节点后的所有节点
@H_
403_0@*ExpandFixtures扩展树中所有代表测试fixture的节点。
@H_
403_0@*CollapseFixtures折叠树中所有代表测试fixture的节点。
@H_
403_0@*Properties
显示树中现所选节点的
属性。
@H_
403_0@*Tools
菜单由这些项:
@H_
403_0@*SaveResultsasXML作为一XML
文件保存运行测试的结果。
@H_
403_0@*Options让你定制NUnit的行为。
@H_
403_0@
@H_
403_0@现在看看右边,你已经熟悉Run按钮和进度条。这里还有一个紧跟Run按钮的Stop按钮:点击这个按钮会终止执行正运行的测试。进度条下面是一个文本窗口,在它上方,由以下4个
标签:
@H_
403_0@
@H_
403_0@*ErrorsandFailures窗口
显示失败的测试。在我们的例子里,这个窗口是空。
@H_
403_0@*TestsNotRun窗口
显示没有得到执行的测试。
@H_
403_0@*Console.Error窗口
显示运行测试产生的
错误消息。这些此消息是应用程序
代码使用Console.Error
输出流可以
输出的。
@H_
403_0@*Console.Out窗口
显示运行测试打印到Console.Error
输出流的文本消息。
@H_
403_0@
@H_
403_0@2.2一些常用
属性
@H_
403_0@接下来,我将讲述这个框架如何使用.同时也涉及到一些非常重要的概念,我想其客户
属性是非常重要的.在NUnit里,有以下几种
属性:
@H_
403_0@
@H_
403_0@*TestFixture
@H_
403_0@*Test
@H_
403_0@
@H_
403_0@下面我将对每种
属性一一讲解.
@H_
403_0@TestFixtureAttribute
@H_
403_0@本
属性标记一个类包含测试,当然setup和teardown
方法可有可无.(关于setup和teardown
方法在后面介绍)
@H_
403_0@做为一个测试的类,这个类还有一些限制
@H_
403_0@
@H_
403_0@*必须是Public,否则NUnit看不到它的存在.
@H_
403_0@*它必须有一个缺省的构造
函数,否则是NUnit不会构造它.
@H_
403_0@*构造
函数应该没有任何副作用,因为NUnit在运行时经常会构造这个类多次,如果要是构造
函数要什么副作用的话,那不是乱了.
@H_
403_0@
@H_
403_0@举个例子
@H_
403_0@
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3namespaceMyTest.Tests
@H_
403_0@4{
@H_
403_0@5
@H_
403_0@6[TestFixture]
@H_
403_0@7publicclassPriceFixture
@H_
403_0@8{
@H_
403_0@9//
@H_
403_0@10}
@H_
403_0@11}
@H_
403_0@12
@H_
403_0@
@H_
403_0@TestAttribute
@H_
403_0@Test
属性用来
标记一个类(已经
标记为TestFixture)的某个
方法是可以测试的.为了和先前的版本向后兼容,头4个字符(“test”)忽略大小写.(参看
http://nunit.org/test.html)
@H_
403_0@这个测试
方法可以定义为:
@H_
403_0@
@H_
403_0@publicvoidMethodName()
@H_
403_0@
@H_
403_0@从上面可以看出,这个
方法没有任何参数,其实测试
方法必须没有参数.如果我们定义
方法不对的话,这个
方法不会出现在测试
方法列表中.也就是说在NUnit的界面左边的工作域内,看不到这个
方法.还有一点就是这个
方法不返回任何参数,并且必须为Public.
@H_
403_0@例如:
@H_
403_0@
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3
@H_
403_0@4namespaceMyTest.Tests
@H_
403_0@5{
@H_
403_0@6[TestFixture]
@H_
403_0@7publicclassSuccessTests
@H_
403_0@8{
@H_
403_0@9[Test]publicvoidTest1()
@H_
403_0@10{/**//**/}
@H_
403_0@11}
@H_
403_0@12}
@H_
403_0@13
@H_
403_0@14
@H_
403_0@
@H_
403_0@一般来说,有了上面两个
属性,你可以做基本的事情了.
@H_
403_0@
@H_
403_0@另外,我们再对如何进行比较做一个描述。
@H_
403_0@在NUnit中,用Assert(断言)进行比较,Assert是一个类,它
包括以下
方法:AreEqual,AreSame,Equals,Fail,Ignore,IsFalse,IsNotNull,具体请参看NUnit的文档。
@H_
403_0@
@H_
403_0@3.如何在.NET中应用NUnit
@H_
403_0@我将举个例子,一步一步演示如何去使用NUnit.
@H_
403_0@第1步.为测试
代码创建一个VisualStu
dio工程。
@H_
403_0@在MicrosoftVisualStu
dio.NET中,让我们开始创建一个新的工程。选择VisualC#工程作为工程类型,ClassLibrary作为模板。将工程命名为NUnitQuickStart.图4-1是一个描述本步骤的VisualStu
dio.NET。
@H_
403_0@
@H_
403_0@图4-1:创建第一个NUnit工程
@H_
403_0@第2步.
增加一个NUnit框架引用
@H_
403_0@在MicrosoftVisualStu
dio.NET里创建这个例子时,你需要
增加一个NUnit.framework.dll引用,如下:
@H_
403_0@在SolutionExplorer右击引用,然后选择
增加引用
@H_
403_0@NUnit.framework组件,在AddReference对话框中按Select和OK按钮。
@H_
403_0@图4-2描述了这步:
@H_
403_0@
@H_
403_0@图4-2:
增加一个NUnit.framework.dll引用到工程
@H_
403_0@第3步.为工程加一个类.
@H_
403_0@为工程加一个NumbersFixture类。这里是这个例子的
代码。
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3
@H_
403_0@4namespaceNUnitQuickStart
@H_
403_0@5{
@H_
403_0@6[TestFixture]
@H_
403_0@7publicclassNumersFixture
@H_
403_0@8{
@H_
403_0@9[Test]
@H_
403_0@10publicvoidAddTwoNumbers()
@H_
403_0@11{
@H_
403_0@12inta=1;
@H_
403_0@13intb=2;
@H_
403_0@14intsum=a+b;
@H_
403_0@15Assert.AreEqual(sum,3);
@H_
403_0@16}
@H_
403_0@17}
@H_
403_0@18}
@H_
403_0@19
@H_
403_0@第4步.建立你的VisualStu
dio工程,使用NUnit-Gui测试
@H_
403_0@从程序->NUnit2.2打开NUnit-gui,加载本本工程编译的程序集.
@H_
403_0@为了在VisualStu
dio.NET中
自动运行NUnit-Gui,你需要建立NUnit-Gui作为你的启动程序:
@H_
403_0@在SolutionExplorer里右击你的NunitQuickStart工程。
@H_
403_0@在弹出
菜单中选择
属性。
@H_
403_0@在
显示的对话框的左面,点击ConfigurationProperties夹
@H_
403_0@选择出现在ConfigurationProperties夹下的Debugging。
@H_
403_0@在
属性框右边的StartAction部分,选择下拉框的Program作为DebugMode值。
@H_
403_0@按Apply按钮
@H_
403_0@设置NUnit-gui.exe作为StartApplication。,你既可以键入nunit-gui.exe的全路径,也可使用浏览按钮来指向它。
@H_
403_0@图4-3帮助描述本步骤:
@H_
403_0@
@H_
403_0@图4-3:将NUnit-Gui作为工程的测试运行器
@H_
403_0@第5步.编译运行测试.
@H_
403_0@现在编译solution。成功编译后,开始应用程序。NUnit-Gui测试运行器出现。当你第一次开始NUnit-Gui,它打开时没有测试加载。从File
菜单选择Oprn,浏览NUnitQuickStart.dll的路径。当你加载了测试的程序集,测试运行器为加载的程序集的测试产生一个可见的表现。在例子中,测试程序集仅有一个测试,测试程序集的结构如图4-4所示:
@H_
403_0@
@H_
403_0@图4-4:测试程序集的测试在NUnit-Gui中的视图
@H_
403_0@按Run按钮。树的节点变为绿色,而且测试运行器窗口上的进度条变绿,绿色代表成功通过。
@H_
403_0@
@H_
403_0@4.其他的一些核心概念
@H_
403_0@上面的例子介绍了基本的NUnit特性和
功能.TestFixture,Test,和Assert是3个最基本的特征,我们可以用这些特性进行程序员测试了.但是有的时候,你觉得这3个远远不够,比如有的时候打开一个
数据库连接多次,有没有只让它打开一次的
方法呢?如果我想把测试
分类,应该怎样实现呢?如果我想忽略某些测试,又应该如何去完成呢?不用担心,NUnit已经有这样的
功能了.
@H_
403_0@下面我们一一作出回答.
@H_
403_0@SetUp/TearDown
属性
@H_
403_0@在早期给的testfixture定义里,我们说testfixture的测试是一组常规运行时资源.在测试完成之后,或是在测试执行种,或是释放或清除之前,这些常规运行时资源在一确定的方式上可能需要
获取和初始化.NUnit使用2个额外的
属性:SetUp和TearDown,就
支持这种常规的初始化/清除.我们上面的例子来描述这个
功能.让我们
增加乘法.
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3
@H_
403_0@4namespaceNUnitQuickStart
@H_
403_0@5{
@H_
403_0@6[TestFixture]
@H_
403_0@7publicclassNumersFixture
@H_
403_0@8{
@H_
403_0@9[Test]
@H_
403_0@10publicvoidAddTwoNumbers()
@H_
403_0@11{
@H_
403_0@12inta=1;
@H_
403_0@13intb=2;
@H_
403_0@14intsum=a+b;
@H_
403_0@15Assert.AreEqual(sum,3);
@H_
403_0@16}
@H_
403_0@17[Test]
@H_
403_0@18publicvoidMultiplyTwoNumbers()
@H_
403_0@19{
@H_
403_0@20inta=1;
@H_
403_0@21intb=2;
@H_
403_0@22intproduct=a*b;
@H_
403_0@23Assert.AreEqual(2,product);
@H_
403_0@24}
@H_
403_0@25
@H_
403_0@26}
@H_
403_0@27}
@H_
403_0@28
@H_
403_0@我们仔细一看,不对,有重复的
代码,如何
去除重复的
代码呢?我们可以
提取这些
代码到一个独立的
方法,然后标志这个
方法为SetUp
属性,这样2个测试
方法可以共享对操作数的初始化了,这里是改动后的
代码:
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3
@H_
403_0@4namespaceNUnitQuickStart
@H_
403_0@5{
@H_
403_0@6[TestFixture]
@H_
403_0@7publicclassNumersFixture
@H_
403_0@8{
@H_
403_0@9privateinta;
@H_
403_0@10privateintb;
@H_
403_0@11[SetUp]
@H_
403_0@12publicvoidInitializeOperands()
@H_
403_0@13{
@H_
403_0@14a=1;
@H_
403_0@15b=2;
@H_
403_0@16}
@H_
403_0@17
@H_
403_0@18[Test]
@H_
403_0@19publicvoidAddTwoNumbers()
@H_
403_0@20{
@H_
403_0@21intsum=a+b;
@H_
403_0@22Assert.AreEqual(sum,3);
@H_
403_0@23}
@H_
403_0@24[Test]
@H_
403_0@25publicvoidMultiplyTwoNumbers()
@H_
403_0@26{
@H_
403_0@27intproduct=a*b;
@H_
403_0@28Assert.AreEqual(2,product);
@H_
403_0@29}
@H_
403_0@30
@H_
403_0@31}
@H_
403_0@32}
@H_
403_0@33
@H_
403_0@
@H_
403_0@这样NUnit将在执行每个测试前执行
标记SetUp
属性的
方法.在本例中就是执行InitializeOperands()
方法.记住,这里这个
方法必须为public,不然就会有以下
错误:InvalidSetuporTearDownmethodsignature
@H_
403_0@
@H_
403_0@ExpectedException
@H_
403_0@这里是一个验证这个假设的测试.有的时候,我们知道某些操作会有异常出现,例如,在实例中
增加除法,某个操作被0除,抛出的异常和.NET文档描述的一样.参看以下源
代码.
@H_
403_0@
@H_
403_0@1[Test]
@H_
403_0@2[ExpectedException(typeof(DivideByZeroException))]
@H_
403_0@3publicvoidDivideByZero()
@H_
403_0@4{
@H_
403_0@5intzero=0;
@H_
403_0@6intinfinity=a/zero;
@H_
403_0@7Assert.Fail("Shouldhavegottenanexception");
@H_
403_0@8}
@H_
403_0@9
@H_
403_0@
@H_
403_0@除了[Test]
属性之外,DivideByZero
方法有另外一个客户
属性:ExpectedException.在这个
属性里,你可以在执行过程中捕获你期望的异常类型,例如在本例就是DivideByZeroException.如果这个
方法在没有抛出期望异常的情况下完成了,这个测试失败.使用这个
属性帮助我们写程序员测试验证边界条件(BoundaryConditions).
@H_
403_0@Ignore
属性
@H_
403_0@由于种种原因,有一些测试我们不想运行.当然,这些原因可能
包括你认为这个测试还没有完成,这个测试正在重构之中,这个测试的需求不是太明确.但你有不想破坏测试,不然进度条可是红色的哟.怎么办?使用Ignore
属性.你可以保持测试,但又不运行它们.让我们
标记MultiplyTwoNumbers测试
方法为Ignore
属性:
@H_
403_0@
@H_
403_0@1[Test]
@H_
403_0@2[Ignore("Multiplicationisignored")]
@H_
403_0@3publicvoidMultiplyTwoNumbers()
@H_
403_0@4{
@H_
403_0@5intproduct=a*b;
@H_
403_0@6Assert.AreEqual(2,product);
@H_
403_0@7}
@H_
403_0@
@H_
403_0@运行测试,现在产生了下面的
输出(在图5-1
显示):
@H_
403_0@
@H_
403_0@图5-1:在一个程序员测试中使用Ignore
属性
@H_
403_0@Ignore
属性可以附加到一个独立的测试
方法,也可以附加到整个测试类(TestFixture).如果Ignore
属性附加到TestFixture,所有在fixture的测试都被忽略.
@H_
403_0@TestFixtureSetUp/TestFixtureTearDown
@H_
403_0@有时,一组测试需要的资源太昂贵.例如,
数据库连接可能是一个关键资源,在一个testfixture的每个测试中,打开/
关闭数据库连接可能非常慢.这就是我在开始提到的问题.如何
解决?NUnit有一对类似于前面讨论的SetUp/TearDown的
属性:TestFixtureSetUp/TestFixtureTearDown.正如他们名字表明的一样,这些
属性用来
标记为整个testfixture初始化/释放资源
方法一次的
方法.
@H_
403_0@例如,如果你想为所有testfixture的测试共享相同的
数据库连接对象,我们可以写一个打开
数据库连接的
方法,
标记为TestFixtureSetUp
属性,编写另外一个
关闭数据库连接的
方法,
标记为TestFixtureTearDown
属性.这里是描述这个的例子.
@H_
403_0@
@H_
403_0@1usingNUnit.Framework;
@H_
403_0@2
@H_
403_0@3[TestFixture]
@H_
403_0@4publicclassDatabaseFixture
@H_
403_0@5{
@H_
403_0@6[TestFixtureSetUp]
@H_
403_0@7publicvoidOpenConnection()
@H_
403_0@8{
@H_
403_0@9//opentheconnectiontothedatabase
@H_
403_0@10}
@H_
403_0@11
@H_
403_0@12[TestFixtureTearDown]
@H_
403_0@13publicvoidCloseConnection()
@H_
403_0@14{
@H_
403_0@15//closetheconnectiontothedatabase
@H_
403_0@16}
@H_
403_0@17
@H_
403_0@18[SetUp]
@H_
403_0@19publicvoidCreateDataba
SEObjects()
@H_
403_0@20{
@H_
403_0@21//inserttherecordsintothedatabasetable
@H_
403_0@22}
@H_
403_0@23
@H_
403_0@24[TearDown]
@H_
403_0@25publicvoidDeleteDataba
SEObjects()
@H_
403_0@26{
@H_
403_0@27//removetheinsertedrecordsfromthedatabasetable
@H_
403_0@28}
@H_
403_0@29
@H_
403_0@30[Test]
@H_
403_0@31publicvoidReadOneObject()
@H_
403_0@32{
@H_
403_0@33//loadonerecordusingtheopendatabaseconnection
@H_
403_0@34}
@H_
403_0@35
@H_
403_0@36[Test]
@H_
403_0@37publicvoidReadManyObjects()
@H_
403_0@38{
@H_
403_0@39//loadmanyrecordsusingtheopendatabaseconnection
@H_
403_0@40}
@H_
403_0@41}
@H_
403_0@42
@H_
403_0@43
@H_
403_0@
@H_
403_0@TestSuite
@H_
403_0@TestSuite是testcase或其他testsuite的集合.合成(Composite),模式描述了testcase和testsuite之间的关系.
@H_
403_0@参考来自NUnit的关于Suite的
代码
@H_
403_0@SuiteAttribute
@H_
403_0@1namespaceNUnit.Tests
@H_
403_0@2{
@H_
403_0@3usingSystem;
@H_
403_0@4usingNUnit.Framework;
@H_
403_0@5
@H_
403_0@6
@H_
403_0@7
@H_
403_0@8publicclassAllTests
@H_
403_0@9{
@H_
403_0@10[Suite]
@H_
403_0@11publicstaticTestSuiteSuite
@H_
403_0@12{
@H_
403_0@13get
@H_
403_0@14{
@H_
403_0@15TestSuitesuite=newTestSuite("AllTests");
@H_
403_0@16suite.Add(newOneTestCase());
@H_
403_0@17suite.Add(newAssemblies.AssemblyTests());
@H_
403_0@18suite.Add(newAssertionTest());
@H_
403_0@19returnsuite;
@H_
403_0@20}
@H_
403_0@21}
@H_
403_0@22}
@H_
403_0@23}
@H_
403_0@24
@H_
403_0@Category
属性
@H_
403_0@对于测试来说,你有的时候需要将之
分类,此
属性正好就是用来
解决这个问题的。
@H_
403_0@你可以选择你需要运行的测试类目录,也可以选择除了这些目录之外的测试都可以运行。在命令行环境里/include和/exclude来实现。在GUI环境下,就更简单了,选择左边工作域里的CatagoriesTab,选择Add和Remove既可以了。
@H_
403_0@在上面的例子上做了一些改善,
代码如下:
@H_
403_0@
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3
@H_
403_0@4namespaceNUnitQuickStart
@H_
403_0@5{
@H_
403_0@6[TestFixture]
@H_
403_0@7publicclassNumersFixture
@H_
403_0@8{
@H_
403_0@9privateinta;
@H_
403_0@10privateintb;
@H_
403_0@11[SetUp]
@H_
403_0@12publicvoidInitializeOperands()
@H_
403_0@13{
@H_
403_0@14a=1;
@H_
403_0@15b=2;
@H_
403_0@16}
@H_
403_0@17
@H_
403_0@18[Test]
@H_
403_0@19[Category("Numbers")]
@H_
403_0@20publicvoidAddTwoNumbers()
@H_
403_0@21{
@H_
403_0@22intsum=a+b;
@H_
403_0@23Assert.AreEqual(sum,3);
@H_
403_0@24}
@H_
403_0@25
@H_
403_0@26[Test]
@H_
403_0@27[Category("Exception")]
@H_
403_0@28[ExpectedException(typeof(DivideByZeroException))]
@H_
403_0@29publicvoidDivideByZero()
@H_
403_0@30{
@H_
403_0@31intzero=0;
@H_
403_0@32intinfinity=a/zero;
@H_
403_0@33Assert.Fail("Shouldhavegottenanexception");
@H_
403_0@34}
@H_
403_0@35[Test]
@H_
403_0@36[Ignore("Multiplicationisignored")]
@H_
403_0@37[Category("Numbers")]
@H_
403_0@38publicvoidMultiplyTwoNumbers()
@H_
403_0@39{
@H_
403_0@40intproduct=a*b;
@H_
403_0@41Assert.AreEqual(2,product);
@H_
403_0@42}
@H_
403_0@43
@H_
403_0@44}
@H_
403_0@45
@H_
403_0@
@H_
403_0@NUnit-GUI界面如图5-2:
@H_
403_0@
@H_
403_0@
@H_
403_0@
@H_
403_0@图5-2:使用Catagories
属性的界面
@H_
403_0@
@H_
403_0@Explicit
属性
@H_
403_0@本
属性忽略一个test和testfixture,直到它们显式的选择执行。如果test和testfixture在执行的过程中被发现,就忽略他们。所以,这样一来进度条
显示为黄色,因为有test或testfixture忽略了。
@H_
403_0@例如:
@H_
403_0@
@H_
403_0@1
@H_
403_0@2[Test,Explicit]
@H_
403_0@3[Category("Exception")]
@H_
403_0@4[ExpectedException(typeof(DivideByZeroException))]
@H_
403_0@5publicvoidDivideByZero()
@H_
403_0@6{
@H_
403_0@7intzero=0;
@H_
403_0@8intinfinity=a/zero;
@H_
403_0@9Assert.Fail("Shouldhavegottenanexception");
@H_
403_0@10}
@H_
403_0@11
@H_
403_0@为什么会设计成这样呢?原因是Ingore
属性忽略了某个test或testfixture,那么他们你再想
调用执行是不可能的。那么万一有一天我想
调用被忽略的test或testfixture怎么办,就用Explicit
属性了。我想这就是其中的原因吧。
@H_
403_0@ExpectedException
属性
@H_
403_0@期望在运行时抛出一个期望的异常,如果是,则测试通过,否则不通过。
@H_
403_0@参看下面的例子:
@H_
403_0@1[Test]
@H_
403_0@2[ExpectedException(typeofInvalidOperationException))]
@H_
403_0@3publicvoidExpectAnException()
@H_
403_0@4{
@H_
403_0@5intzero=0;
@H_
403_0@6intinfinity=a/zero;
@H_
403_0@7Assert.Fail("Shouldhavegottenanexception");
@H_
403_0@8
@H_
403_0@9}
@H_
403_0@10
@H_
403_0@在本测试中,应该抛出DivideByZeroException,但是期望的是InvalidOperationException,所以不能通过。如果我们将[ExpectedException(typeof(InvalidOperationException))]改为[ExpectedException(typeof(DivideByZeroException))],本测试通过。
@H_
403_0@5.测试生命周期合约
@H_
403_0@如果记得testcase的定义,其中一个
属性是测试的独立性或隔离性.SetUp/TearDown
方法提供达到测试隔离性的目的.SetUp确保共享的资源在每个测试运行前正确初始化,TearDown确保没有运行测试产生的遗留副作用.TestFixtureSetUp/TestFixtureTearDown同样提供相同的目的,但是却在testfixture范围里,我们刚才描述的
内容组成了测试框架的运行时容器(testrunner)和你写的测试之间的生命周期合约(life-cyclecontract).
@H_
403_0@为了描述这个合约,我们写一个简单的测试来说明什么
方法调用了,怎么合适
调用的.这里是
代码:
@H_
403_0@
@H_
403_0@1usingSystem;
@H_
403_0@2usingNUnit.Framework;
@H_
403_0@3[TestFixture]
@H_
403_0@4publicclassLifeCycleContractFixture
@H_
403_0@5{
@H_
403_0@6[TestFixtureSetUp]
@H_
403_0@7publicvoidFixtureSetUp()
@H_
403_0@8{
@H_
403_0@9Console.Out.WriteLine("FixtureSetUp");
@H_
403_0@10}
@H_
403_0@11
@H_
403_0@12[TestFixtureTearDown]
@H_
403_0@13publicvoidFixtureTearDown()
@H_
403_0@14{
@H_
403_0@15Console.Out.WriteLine("FixtureTearDown");
@H_
403_0@16}
@H_
403_0@17
@H_
403_0@18[SetUp]
@H_
403_0@19publicvoidSetUp()
@H_
403_0@20{
@H_
403_0@21Console.Out.WriteLine("SetUp");
@H_
403_0@22}
@H_
403_0@23
@H_
403_0@24[TearDown]
@H_
403_0@25publicvoidTearDown()
@H_
403_0@26{
@H_
403_0@27Console.Out.WriteLine("TearDown");
@H_
403_0@28}
@H_
403_0@29
@H_
403_0@30[Test]
@H_
403_0@31publicvoidTest1()
@H_
403_0@32{
@H_
403_0@33Console.Out.WriteLine("Test1");
@H_
403_0@34}
@H_
403_0@35
@H_
403_0@36[Test]
@H_
403_0@37publicvoidTest2()
@H_
403_0@38{
@H_
403_0@39Console.Out.WriteLine("Test2");
@H_
403_0@40}
@H_
403_0@41
@H_
403_0@42}
@H_
403_0@43
@H_
403_0@44
@H_
403_0@
@H_
403_0@当编译和运行这个测试,可以在System.Console窗口看到下面的
输出:
@H_
403_0@
@H_
403_0@FixtureSetUp
@H_
403_0@SetUp
@H_
403_0@Test1
@H_
403_0@TearDown
@H_
403_0@SetUp
@H_
403_0@Test2
@H_
403_0@TearDown
@H_
403_0@FixtureTearDown
@H_
403_0@
@H_
403_0@可以看到,SetUp/TearDown
方法调用在每个测试
方法的前后.整个fixture
调用一次TestFixtureSetUp/TestFixtureTearDown
方法.
@H_
403_0@
@H_
403_0@参考
@H_
403_0@1)
http://www.nunit.org
@H_
403_0@2)JamesW.NewkirkandAlexeiA.Vorontsov,Test-DrivenDevelopmentinMicrosoft.NET,MicrosoftPress,2003
@H_
403_0@3)
http://www.testdriven.com
@H_
403_0@4)KentBeck,Test-DrivenDevelopment:ByExample,Addison-WesleyProfessional,2003
@H_
403_0@5)AndrewHunt,DavidThomas,PragmaticUnitTestingInC#WithNUnit
@H_
403_0@6)NUnit
中文文档:
http://www.36sign.com/nunit LastUpdated:2005年6月23日 LastUpdated:2007年4月12日