时间:2011/11/21 版权所有,侵权必究。
出处: http://blog.csdn.net/snowshinoy
在了解了NUnit的对象识别断言后(【Nunit入门系列讲座 4】NUnit断言- 对象识别断言),本想继续带大家深入了解Nunit的断言系统。不过,断言的种类很多,而内容又相对枯燥,为了不打击大家学习的兴趣,所以今天我们换个口味,来学习一个全新的内容——NUnit的异常测试。说到异常,其实很多朋友都有所耳闻,甚至很多朋友会对它有所忌讳,认为异常就意味着程序的错误,是一个坏消息的代名词。事实确实如此么?我们就来一起探讨下,并学会在NUnit中编写针对异常的测试。
一、好的程序才有异常?
其实不仅仅在.NET,早在C++中就有了异常机制。现在一个优秀的语言的标志之一,就是是否良好支持异常机制。异常顾名思义,就是异于正常,也就是不符合正常流程的事情发生了。那如何理解这段的标题呢?菩萨大人教导我们:“不怕念起,只怕觉迟”,就是说,不怕坏事情将要发生,就怕你不知道。我们在程序中的异常,就是我们在程序中发现错误的一种手段。有了异常,我们就可以先知先觉,在错误造成问题之前,把他们处理掉。下面我们看一个例子,顺便了解下.net中异常的定义和应用方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExceptionExample
{
class Exp
{
static void Main(string[] args)
{
int[] array1 = new int[] { 1, 3, 5, 7, 9 };
Console.WriteLine(array1[5]);
}
}
}
这个例子里定义了一个数组,包含五个元素,然后打印出这个数组的第六个元素。运行一下,看看会出现什么情况。
很显然,程序崩溃了。因为这是一个系统可以识别的异常,所以异常被显示了出来。这样的程序显然不能接受,那我们应该怎么样呢。最好是告诉用户,访问第6个元素是不可能的,因为我们的数组只有5个元素。这样用户看来,这个程序不是崩溃了,而是自己提了不合理的要求(不过他也不会脸红的)。修改代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExceptionExample
{
class Exp
{
static void Main(string[] args)
{
int[] array1 = new int[] { 1, 3, 5, 7, 9 };
try
{
Console.WriteLine(array1[5]);
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("coule not access the sixth element,we only have " + array1.Length+" elements in arry1");
}
}
}
}
现在再次运行一下新的程序,看下结果如何
恩,现在好多了。大家从这个例子里就可以初步看出,异常机制是帮助我们发现程序中的一些错误情况,然后在我们的代码中,插入一些针对这些错误情况的处理。这个过程,就叫做异常捕获及处理。异常机制的实现原理较为复杂,我们在本教程中不做详述,但是可以把try想象成一个监控块,这个块内一旦出现了异常,就会被发现,然后跳转到异常对应的catch中去执行。Catch中的语句就是对这类异常的处理过程。
二、在NUnit中对异常进行测试
既然异常是一种帮助我们编写健壮程序的良好机制,那么我们的很多模块一定就具备一些抛出异常的代码,用来通知应用模块某种错误或者情况的发生,以便我们的应用代码对这些情况做出相应的处理。而这种异常抛出,也是我们需要进行测试的一个方面。可以想见,一个本该抛出的异常,因为某种原因,没有抛出或者抛出了错误的异常,就会导致上层应用作出错误的处理。轻则影响软件的某些局部功能,严重的甚至会直接让整个软件崩溃,这种例子在软件开发中是屡见不鲜的。
NUnit也提供了很多办法让我们在测试中添加针对异常的测试,包括一些属性和断言。 我们现在来了解下NUnit用于测试异常的一个属性。
[ExpectedException( "System.ArgumentException", ExpectedMessage="expected message",UserMessage ="custom message" )]
这个属性加在定义测试的函数上,用来告诉NUnit,这个测试要求抛出一个指定类型的异常,并且异常的Message属性与ExpectedMessage定义的一致。如果没有在测试中捕获这类异常,就测试失败,并输出UserMessage定义的信息作为错误信息。按照惯例,我们将在实例中学习到如何使用这个属性来测试异常。
为了说明问题,我们设计了一个叫做Garage的模块,这个模块模拟了一个容纳5辆车的车库,提供2个方法来实现入库、出库功能(CheckIn和CheckOut)。同时提供了一个管理的功能,即开启/关闭车库(Open和Close,我们的这个车库不是24小时营业),见如下对象接口图:
整个车库模块提供了2大类异常
GarageException:这个异常主要用来体现车库本身的功能性错误,每种错误通过异常的Message属性来区分。比如“Garage Closed”表示车库操作时候车库不在营业状态的错误,“Garage Full”表示车库已满时候使用了CheckIn功能导致的错误。
privilegeException:这个异常用来体现对车库的非常管理操作。车库的Open和Close操作都需要提供密码,如果密码不对,就会有这样的异常发生。
整个模块对于异常的设计如下:
1. 如果在密码错误的情况下对车库进行管理操作(Open和Close),需要抛出privilegeException</