您的位置:首页 > 其它

NUnit2.0详细使用方法 (转)

2005-08-30 09:46 447 查看
NUnit2.0详细使用方法
前一段时间,有人问我在.NET里如何进行TDD开发.这个问题促使我想对NUnit做一个详细的介绍.因为我们大家都知道NUnit是在.NET进行TDD的利器.
如果你已经知道很多关于NUnit的应用,请指出我的不对之处和提出一些建议,使本文更加完善.如果你对NUnit还不是很了解的话,我建议你还是阅读一下.
本文分为以下部分:

1.TDD的简介

首先什么是TDD呢?Kent Beck在他的<<测试驱动开发 >>(Addison-Wesley Professional,2003)一书中,使用下面2个原则来定义TDD:
· 除非你有一个失败的自动测试,永远不要写一单行代码.
· 阻止重复
我想第一个原则是显而易见的.在没有失败的自动测试下就不要写代码.因为测试是嵌入在代码必须满足的需求中.如果没有需求,就没有必要实现任何东西.所以这个原则阻止我们去实现那些没有测试和在解决方案中不需要的功能.
第二个原则说明了在一个程序中,不应该包含重复的代码.如果代码重复,我想这就是不好的软件设计的象征.随着时间的流逝,它会对程序造成不一致的问题,并且使代码变非常混乱 ,因为我们时常不会记得重复代码的位置.如果发现代码重复,我想我们应该立即删除代码重复.其实这就涉及到重构了.在这里我就不多讲了.
一般来说,测试分为2种类型,一是程序员自己的测试,另外一种是客户的测试.关于客户测试,我推荐一个FIT的框架,非常不错。在这里,我们讲的TDD就是程序员测试.那么什么是程序员测试呢?我认为就是我们常说的单元测试.既然是单元测试,在.NET里势必会用到某些工具,目前最著名恐怕就是我即将介绍的NUnit了,

2.NUnit的介绍

NUnit是一个单元测试框架,专门针对于.NET来写的.其实在前面有JUnit(Java),CPPUnit(C++),他们都是xUnit的一员.最初,它是从JUnit而来.现在的版本是2.2.接下来我所用的都是基于这个版本.
NUnit最初是由James W.Newkirk, Alexei A.Vorontsov 和Philip A.Craig, 后来开发团队逐渐庞大起来.在开发过程中, Kent Beck 和Erich Gamma2位牛人也提供了许多帮助.看来对于NUnit还真是下了一番力气了.J
NUnit是xUnit家族种的第4个主打产品,完全由C#语言来编写,并且编写时充分利用了许多.NET的特性,比如反射,客户属性等等.
最重要的一点是它适合于所有.NET语言.
如果你还没有下载,可以到http://www.nunit.org/去下载.

2.1 NUnit的介绍

Ok,下面正式讲解NUnit.在讲解之前,看看几张图片:
using System;
2 using NUnit.Framework;
3 namespace MyTest.Tests
4 [/code]

TestAttribute

Test属性用来标记一个类(已经标记为TestFixture)的某个方法是可以测试的.为了和先前的版本向后兼容,头4个字符(“test”)忽略大小写.(参看http://nunit.org/test.html)
这个测试方法可以定义为:
public void MethodName()

从上面可以看出,这个方法没有任何参数,其实测试方法必须没有参数.如果我们定义方法不对的话,这个方法不会出现在测试方法列表中.也就是说在NUnit的界面左边的工作域内,看不到这个方法.还有一点就是这个方法不返回任何参数,并且必须为Public.
例如:
1using System;
2using NUnit.Framework;
3
4namespace MyTest.Tests
5
14
一般来说,有了上面两个属性,你可以做基本的事情了.
另外,我们再对如何进行比较做一个描述。
在NUnit中,用Assert(断言)进行比较,Assert是一个类,它包括以下方法:AreEqual,AreSame,Equals, Fail,Ignore,IsFalse,IsNotNull,具体请参看NUnit的文档。

3.如何在.NET中应用NUnit

我将举个例子,一步一步演示如何去使用NUnit.

第1步.为测试代码创建一个Visual Studio工程。

在Microsoft Visual Studio .NET中,让我们开始创建一个新的工程。选择Visual C#工程作为工程类型,Class Library作为模板。将工程命名为NUnitQuickStart.图4-1是一个描述本步骤的Visual Studio .NET。
using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5

第4步.建立你的Visual Studio 工程,使用NUnit-Gui测试

从程序->NUnit2.2打开NUnit-gui,加载本本工程编译的程序集.
为了在Visual Studio .NET中自动运行NUnit-Gui,你需要建立NUnit-Gui作为你的启动程序:
在 Solution Explorer里右击你的NunitQuickStart工程。
在弹出菜单中选择属性。
在显示的对话框的左面,点击Configuration Properties夹
选择出现在Configuration Properties夹下的Debugging。
在属性框右边的Start Action部分,选择下拉框的Program作为Debug Mode值。
按Apply按钮
设置nunit-gui.exe 作为Start Application。,你既可以键入nunit-gui.exe的全路径,也可使用浏览按钮来指向它。
图4-3 帮助描述本步骤:
using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5 我们仔细一看,不对,有重复的代码,如何去除重复的代码呢?我们可以提取这些代码到一个独立的方法,然后标志这个方法为SetUp 属性,这样2个测试方法可以共享对操作数的初始化了,这里是改动后的代码:

1using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5
这样NUnit将在执行每个测试前执行标记SetUp属性的方法.在本例中就是执行InitializeOperands()方法.记住,这里这个方法必须为public,不然就会有以下错误:Invalid Setup or TearDown method signature

ExpectedException

这里是一个验证这个假设的测试.有的时候,我们知道某些操作会有异常出现,例如, 在实例中增加除法,某个操作被0除,抛出的异常和.NET文档描述的一样.参看以下源代码.
1[Test]
2[ExpectedException(typeof(DivideByZeroException))]
3public void DivideByZero()
4

除了[Test]属性之外, DivideByZero方法有另外一个客户属性: ExpectedException.在这个属性里,你可以在执行过程中捕获你期望的异常类型,例如在本例就是DivideByZeroException.如果这个方法在没有抛出期望异常的情况下完成了,这个测试失败.使用这个属性帮助我们写程序员测试验证边界条件(Boundary Conditions).

Ignore 属性

由于种种原因,有一些测试我们不想运行.当然,这些原因可能包括你认为这个测试还没有完成,这个测试正在重构之中,这个测试的需求不是太明确.但你有不想破坏测试,不然进度条可是红色的哟.怎么办?使用Ignore属性.你可以保持测试,但又不运行它们.让我们标记MultiplyTwoNumbers测试方法为Ignore属性:
1[Test]
2[Ignore("Multiplication is ignored")]
3public void MultiplyTwoNumbers()
4using NUnit.Framework;
2
3[TestFixture]
4public class DatabaseFixture
5
43

Test Suite

Test Suite是test case或其他test suite的集合.合成(Composite),模式描述了test case和test suite之间的关系.
参考来自NUnit的关于Suite的代码
Suite Attribute



1namespace NUnit.Tests
2Category属性

对于测试来说,你有的时候需要将之分类,此属性正好就是用来解决这个问题的。
你可以选择你需要运行的测试类目录,也可以选择除了这些目录之外的测试都可以运行。在命令行环境里 /include 和/exclude来实现。在GUI环境下,就更简单了,选择左边工作域里的Catagories Tab,选择Add和Remove既可以了。
在上面的例子上做了一些改善,代码如下:
1using System;
2using NUnit.Framework;
3
4namespace NUnitQuickStart
5
2                        [Test,Explicit]
3                        [Category("Exception")]
4                        [ExpectedException(typeof(DivideByZeroException))]
5                        public void DivideByZero()
6    为什么会设计成这样呢?原因是Ingore属性忽略了某个test或test fixture,那么他们你再想调用执行是不可能的。那么万一有一天我想调用被忽略的test或test fixture怎么办,就用Explicit属性了。我想这就是其中的原因吧。

Expected Exception属性

期望在运行时抛出一个期望的异常,如果是,则测试通过,否则不通过。 参看下面的例子: 1[Test] 2[ExpectedException(typeofInvalidOperationException))] 3public void ExpectAnException() 4 在本测试中,应该抛出DivideByZeroException,但是期望的是InvalidOperationException,所以不能通过。如果我们将[ExpectedException(typeof(InvalidOperationException))]改为[ExpectedException(typeof(DivideByZeroException))],本测试通过。

5 .测试生命周期合约

如果记得test case的定义,其中一个属性是测试的独立性或隔离性.SetUp/TearDown方法提供达到测试隔离性的目的.SetUp确保共享的资源在每个测试运行前正确初始化,TearDown确保没有运行测试产生的遗留副作用. TestFixtureSetUp/TestFixtureTearDown同样提供相同的目的,但是却在test fixture范围里,我们刚才描述的内容组成了测试框架的运行时容器(test runner)和你写的测试之间的生命周期合约(life-cycle contract). 为了描述这个合约,我们写一个简单的测试来说明什么方法调用了,怎么合适调用的.这里是代码: [code] 1using System; 2using NUnit.Framework; 3[TestFixture] 4public class LifeCycleContractFixture 5 44

当编译和运行这个测试,可以在System.Console窗口看到下面的输出:
FixtureSetUp
SetUp
Test 1
TearDown
SetUp
Test 2
TearDown
FixtureTearDown

可以看到, SetUp/TearDown方法调用在每个测试方法的前后. 整个fixture调用一次TestFixtureSetUp/TestFixtureTearDown方法.

下载:
1)NUnit的应用文档 下载
2)本问的PDF版 下载

3)本文的源代码 下载

参考
1) http://www.nunit.org
2) James W.Newkirk and Alexei A.Vorontsov ,Test-Driven Development in Microsoft .NET,Microsoft Press,2003
3) http://www.testdriven.com
4) Kent Beck, Test-Driven Development: By Example ,Addison-Wesley Professional, 2003
5) Andrew Hunt ,David Thomas ,Pragmatic Unit Testing In C# With NUnit

在.NET中如何测试Private和Protected方法?

How to Test Private and Protected methods in .NET, TimStall,
介绍

TDD是1)写测试2)写通过这些测试的代码,3)然后重构的实践.在,NET社区中, 这个概念逐渐变得非常流行,这归功于它所增加的质量保证.此时,它很容易测试public方法,但是一个普遍的问题出现了,”我如何测试Protected和private方法呢?”

本文将:

总结”你是否应该测试private方法的争论?”的一些关键点.
创建一些案例,这些案例仍旧是有用的,至少知道怎样测试private和protected方法—不考虑你站在争论的哪一边.
提供方法和可下载的代码示例来展现这些测试技术.

背后的方法

你是否应该测试private方法?

一个Google查询 向你展示了有很多关于使用private方法的争议,更不用说测试他们了.下面这个表概括了一些关于这个话题的正方和反方的普遍意见.

正方

反方

使用private方法

封装private方法提供了封装,对于终端客户来说,它使代码更易使用
重构更容易重构private方法,一位他们永远不会直接被外部的客户端调用,因此,修改签名(Signature)不会影响任何方法调用.
验证 不像public方法那样必须验证所有输入,因为他们被外部调用时,private方法在类中安全调用,不需要同样严格的验证—输入应该在public方法中已经验证了.
测试范围暴露每个方法为public,将在很大程度上增加测试的范围.private方法仅仅使用在开发者如何去使用他们,然而public方法需要测试每种可能,这就需要一个更广阔的测试范围了.
不能重构如果一个类足够复杂,值得使用private方法,那么它需要重构.
隐藏功能性private方法(如果正确设计)提供有用的客户端可以访问的特性,那么任何private方法都值得测试,并且应该真正为public.
测试Private方法

测试控制private方法可以包含复杂的逻辑,并且它可以增加测试控制来直接访问方法,测试它,来代替通过一个public方法间接访问它.
原则单元测试是测试最小的功能代码片断.private方法是功能型代码片断,因此,基于原则,private方法应该是可测试的.
已经覆盖了仅仅只有public接口才可以测试.private已经测试了, 它是通过测试的public方法调用来完成的.
脆弱的代码如果你重构代码,操作private方法,并且如果你有和这些private相关的测试,你同时也需要操作这些测试.
在这些主题的两方,都有明了并且具有经验的人.因此我不打算,也不期望终结”我是否应该测试private方法”的争论.但是对于双方来说,这里仍有价值来知道如何测试他们,即使你认为private不应该被测试.

如果你至少能表现出你可以测试他们,但是你没有这样做(例如,你没有简单的说”不要测试private方法”,因为你不知道如何去测试),你的观点将更加具有说服力.
测试非public方法的选择让你明白在你的小组中,什么真正做的最好.
只要仍有有效的条件,是值得拥有一种方便的方法来测试他们.

好的原则以及不适当的技术

Andrew Hunt a David Thomas在他们的书中Pragmatic Unit Testing in C# with NUnit, 解释到,好的单元测试是ATRIP:

自动化(Automatic)
彻底(Thorough )
可重复(Repeatable)
独立(Independent )
专业(Professional)

对于测试private/protected方法来说,有另外三个附加原则:

透明(Transparency) - 不要改变测试下的系统(System Under Test ,SUT),例如,在产品代码中增加包装的方法.
范围(Scope) - 可以在Debug和Release下运行
简单(Simplicity) -最小的开销,因此容易修改,并且非常简单引入最小的风险.

记住这些原则,下面是一些不足的策略.

策略

问题

不要使用任何private方法.

它避免这个问题
使用指示符 #if DEBUG ...#endif 来包装一个public方法,这个方法然后包装private方法.单元测试现在可以间接访问那些public方法包装的private方法.(这是一种我使用许多次的方法,并且发现它是单调的,不是面向对象的)

只在Debug下工作.
它是一个过程,而不是面向对象.我们需要在产品代码和单元测试中包装单独的方法.
通过增加public方法,会修改SUT.
Public方法使用[
Conditional(
"DEBUG"
)]
属性包装
private方法.


只在Debug下工作.
创建内部方法来访问private方法.然后在public方法包装那些private方法的程序集的其他地方,创建一个公共的测试类.

通过增加内部钩子,以及最后使得private方法在产品中可用,会改编发布代码.
这需要很多额外得编码,因此使脆弱得.

测试Protected方法

Protected方法仅仅对于它得继承类可见,因此,对于测试套件来说并不是立即可见的.例如,激射我们想测试来自from
ClassLibrary1.MyObject
的方法.

1protected string MyProtectedMethod(string strInput, int i32Value)
2

Pragmatic Unit Testing in C# with NUnit一书解释了一个解决方案:创建一个继承自MyObject类的类MyObjectTester,然后创建一个public方法
TestMyProtectedMethod
,
这个方法包装了那个
protected
方法
.
例如
,
1public new string TestMyProtectedMethod(string strInput, int i32Value)
2
方法很简单,也遵循所有原则:[/code]
原则

实现

透明

通过使用继承,并把
MyObjectTester
类放入
UnitTests
程序集中,它不需要增加任何新的代码到产品程序集中.

范围

在本方法中没有任何东西依赖Debug-only技术.

简单

尽管这个方法需要一新的类,以及每个protected 方法的额外public包装方法,但是它是面向对象的,并且使类型安全的.

测试Private方法

测试private方法需要多做有些工作,但是我们仍可以使用System.Reflection来实现.你可以使用反射来动态访问一种类型的方法, 包括实例和静态private方法的方法.注意访问private方法需要ReflectionPermission,但是对于运行在开发机器或者构建服务器上的单元测试来说,这不是问题.

假设我们想测试来自
ClassLibrary1.MyObject
的private方法
MyPrivateMethod
:

1private string MyPrivateMethod(string strInput, DateTime dt, double
2 dbl)
3
一个解决方法是创建一个UnitTestUtilities工程,这个工程有一个helper类通过反射来调用测试方法.例如,供下载的解决方案在
UnitTestUtilities.Helper
中有如下方法:[/code]
  1public static object RunStaticMethod(System.Type t, string strMethod,
2 object [] aobjParams)
3public static object RunInstanceMethod(System.Type t, string strMethod,
11 object objInstance, object [] aobjParams)
12private static object RunMethod(System.Type t, string
19 strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags)
20
Private方法
RunMethod
带有一些必要的参数,这些参数是反射需要用来调用一个方法,然后返回值的.它有两个public方法
RunStaticMethod
RunInstanceMethod
来为静态和实例方法分别包装这.[/code]
看看
RunMethod
,它首先得到类型的
MethodInfo.
因为我们期望它仅为已经存在的方法调用
.
一个空的方法触发一个
Exception
.
一旦我们有
MethodInfo
,我们就可以调用实例化对象提供的方法(static 方法为null)以及参数数组.

我们可以在一个NUnit测试中像下面使用这个Utility:

1[Test] public void TestPrivateInstanceMethod()
2

原则

实现

透明

我们仅创建的多余代码;
UnitTestUtilities
,它没有带到产品中.

范围

在本方法中没有任何东西依赖Debug-only技术.

简单

Because the method is being dynamically called, the parameters aren't checked at compile time.本方法可以通过一个简单的调用来调用任何方法.一旦你有
UnitTestUtilities
,你唯一要完成的是为
RunInstanceMethod
or
RunStaticMethod
创建正确的参数(方法名,数据类型,等…),因为方法动态的被调用,参数在编译的时候不会得到检查.

总结

关于是否应该测试private方法仍有争论,但是我们有能力去测试他们.我们可以使用继承创
建一个继承类
TesterClass
来测试protected方法.这个继承类包装了其基类的
protected方法为public.我们可以是哦女冠反射来测试private方法,它能够抽象
到一个
UnitTestUtility
helper类.这些技术都能帮助你改进测试覆盖面.

原文:How to Test Private and Protected methods in .NET, TimStall,

原文转自:http://confach.cnblogs.com/archive/2005/06/20/177817.html
http://confach.cnblogs.com/articles/225502.html
作者:

Milestone

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: