作为单元测试的第二部分,和第一部分的间隔时间差的的确有点长了(嘿嘿,自己一直在偷懒)。在第一讲中主要讲的是如何在VS2005中进行单元测试,以及当时选NUnit2.48(.net 2.0)作为学习的版本,和进行了一个小个程序的测试,大致上都知道如何使用NUnit对C#编写的代码如何进行单元测试,而在这一讲中则是主要讲讲几个常用的属性(Attribute)。
先写一个小小的程序,功能只是在一个数组中找出一个最大的数字。
代码
public
int
GetLargest(
int
[] array)
{
if
(
null
==
array
||
0
==
array.Length)
{
throw
new
Exception(
"
数组为空!
"
);
}
int
num
=
Int32.MinValue;
for
(
int
i
=
0
; i
<
array.Length; i
++
)
{
if
(num
<
array[i])
{
num
=
array[i];
}
}
return
num;
}
同样要建立一个测试类,现在开始逐个介绍一些比较常用的属性。
一、[TestFixtureSetUp]这个属性标识的函数表示是这个类的初始化函数,测试类一旦执行,首先执行的就是这个属性标识的函数,既然是初始化,那当然一般是初始化一些对象和字段之类的,功能有点类似于构造函数。
[TestFixtureSetUp]
public
void
Init()
{
largest
=
new
Largest();
Console.WriteLine(
"
我只会在类的最初调用时初始化对象!
"
);
}
二、上面说了初始化,自然的我们要说到销毁了,[TestFixtureTearDown]与初始化对应,此属性标识的函数在类的最后用来销毁对象,根据功能很自然的就想到析构函数。
代码
[TestFixtureTearDown]
public
void
Terminate()
{
if
(
null
!=
largest)
{
largest
=
null
;
}
Console.WriteLine(
"
我只会在类的最后销毁对象!
"
);
}
三、上面说的初始化和销毁都是针对整个测试类来说的,有没有一个可以针对没个测试的case的呢?可以在执行每个case之前进行初始化,在每个case执行之后又可以销毁,这样不就可以让一些公用的对象可以在执行每个case的时候都重新被赋值,不会相互影响。既然都这样说了,当然有了。[SetUp]属性标识的函数可以在每个Test Case的执行之前初始化一次。
[SetUp]
public
void
InitCase()
{
largest
=
new
Largest();
Console.WriteLine(
"
我会在执行每个Test Case之前初始化对象!
"
);
}
四、直接来看销毁[TearDown].
代码
[TearDown]
public
void
TerminateCase()
{
if
(
null
!=
largest)
{
largest
=
null
;
}
Console.WriteLine(
"
我会在执行完每个Test Case之后销毁对象!
"
);
}
五、在程序中我们对应空数组抛出了一个异常,那么我们在测试的时候,如果输入的数组是空的会怎么样?看下面一段程序:
[Test]
public
void
TestGetLargest1()
{
int
[] numArr
=
new
int
[] { };
largest.GetLargest(numArr);
}
很明显,测试肯定会抛出一个异常,不能通过。
那现在我们知道这样输入是不对,那怎么可以屏蔽掉这个异常呢。[ExpectedException],这个实行有几个重载的类型,根据情况自己选择。
代码
[Test]
[ExpectedException(
typeof
(Exception))]
public
void
TestGetLargest2()
{
int
[] numArr
=
new
int
[] { };
largest.GetLargest(numArr);
}
这个时候我们看到的结果不再是提示有异常抛出,而是通过了测试(你都已经预料到有这种异常了,当然不会再提示你程序会抛出这个异常!)。
六、最后简单的提一下其他几个属性:[Ignore]标识的Test Case不会再NUnit的IDE中执行,因为被你忽略掉了。[Explicit]必须要显示的选中这个Case才会被执行,否则是不会执行的。[Category]分组属性,可以将几个Case分到同一个组中,这样就会以组为单位去执行,或不执行。
测试类完整代码贴上:
代码
[TestFixture]
public
class
LargestTest
{
private
Largest largest;
[SetUp]
public
void
InitCase()
{
largest
=
new
Largest();
Console.WriteLine(
"
我会在执行每个Test Case之前初始化对象!
"
);
}
[TearDown]
public
void
TerminateCase()
{
largest
=
null
;
Console.WriteLine(
"
我会在执行完每个Test Case之后销毁对象!
"
);
}
[TestFixtureSetUp]
public
void
Init()
{
largest
=
new
Largest();
Console.WriteLine(
"
我只会在类的最初调用时初始化对象!
"
);
}
[TestFixtureTearDown]
public
void
Terminate()
{
if
(
null
!=
largest)
{
largest
=
null
;
}
Console.WriteLine(
"
我只会在类的最后销毁对象!
"
);
}
[Test]
public
void
TestGetLargest()
{
int
[] numArr
=
new
int
[] {
-
1
,
0
,
2
,
4
,
-
10
};
int
result
=
largest.GetLargest(numArr);
Assert.AreEqual(
4
, result);
}
[Test]
public
void
TestGetLargest1()
{
int
[] numArr
=
new
int
[] { };
largest.GetLargest(numArr);
}
[Test]
[ExpectedException(
typeof
(Exception))]
public
void
TestGetLargest2()
{
int
[] numArr
=
new
int
[] { };
largest.GetLargest(numArr);
}
[Test]
public
void
TestGetLargest3()
{
int
[] numArr
=
new
int
[] {
10
,
10
};
int
result
=
largest.GetLargest(numArr);
Assert.AreEqual(
10
, result);
}
[Test]
[Ignore]
public
void
TestGetLargest4()
{
int
[] numArr
=
null
;
int
result
=
largest.GetLargest(numArr);
}
}
执行结果:
不知道有没有发现个问题,对于这个程序中,测试案例会很多,比如说数组的数全是正数,负数,有正有负,全部数相同时等等,这样不就要写很多重复的测试case,应该有其他的方法吧。呵呵,不妨试试利用XML、文本存储数据来实现。下一部分我准备用XML读取数据来实现。