最近一段时间在研究单元测试,先记录一下学习记录吧。
首先,单元测试的目的,我觉得最主要有以下几点:
1 ,可以保证 code 实现的功能和我们期望的一致。
2 ,当我们增加了新的功能时,常常会破坏原有的代码而不自知, n 久之后,突然发现某诡异 bug ,需要花费很久才能查出来。而有了单元测试,每当你添加新功能,以及新功能的单元测试代码之后,运行一下这个工程的单元测试,马上就能看到你的新功能是否破坏了你的原有功能。
当然,前提是单元测试写的够完整。
3 ,通过单元测试,可以找到很多不易发现的 bug ,比如边界条件错误等。这会使得我们的程序更加健壮。
4 ,对原有代码编写单元测试,常常会发现原有代码由于耦合度过高,不容易测试,这时候,通过令代码更加容易测试而去改善代码得设计。测试驱动重构?汗。。。。。
先举个简单的例子来说明下单元测试的功能,具体使用 NUnit 的方法,后面再说吧,现在就只用例子来说明下 NUnit 的功能。
环境为 .net1.1 vb.net +NUnit2.27
我编了一个对传入整数数组,查找出最大值的方法,代码如下:
首先,单元测试的目的,我觉得最主要有以下几点:
1 ,可以保证 code 实现的功能和我们期望的一致。
2 ,当我们增加了新的功能时,常常会破坏原有的代码而不自知, n 久之后,突然发现某诡异 bug ,需要花费很久才能查出来。而有了单元测试,每当你添加新功能,以及新功能的单元测试代码之后,运行一下这个工程的单元测试,马上就能看到你的新功能是否破坏了你的原有功能。
当然,前提是单元测试写的够完整。
3 ,通过单元测试,可以找到很多不易发现的 bug ,比如边界条件错误等。这会使得我们的程序更加健壮。
4 ,对原有代码编写单元测试,常常会发现原有代码由于耦合度过高,不容易测试,这时候,通过令代码更加容易测试而去改善代码得设计。测试驱动重构?汗。。。。。
先举个简单的例子来说明下单元测试的功能,具体使用 NUnit 的方法,后面再说吧,现在就只用例子来说明下 NUnit 的功能。
环境为 .net1.1 vb.net +NUnit2.27
我编了一个对传入整数数组,查找出最大值的方法,代码如下:
1
2 Public Class Class1 Class Class1
3 ''' -----------------------------------------------------------------------------
4 ''' <summary>
5 ''' 查找最大值
6 ''' </summary>
7 ''' <param name="list"> 传入整数数组 </param>
8 ''' <returns> 返回数组中的最大值 </returns>
9 ''' <remarks>
10 ''' </remarks>
11 ''' <history>
12 ''' [Tony] 2006-4-20 Created
13 ''' </history>
14 ''' -----------------------------------------------------------------------------
15 Public Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
16 Dim i As Int32
17 Dim max As Int32
18
19 For i = 0 To list.Length - 1
20 If list(i) > max Then
21 max = list(i)
22 End If
23 Next
24
25 Return max
26 End Function
27
28 End Class
2 Public Class Class1 Class Class1
3 ''' -----------------------------------------------------------------------------
4 ''' <summary>
5 ''' 查找最大值
6 ''' </summary>
7 ''' <param name="list"> 传入整数数组 </param>
8 ''' <returns> 返回数组中的最大值 </returns>
9 ''' <remarks>
10 ''' </remarks>
11 ''' <history>
12 ''' [Tony] 2006-4-20 Created
13 ''' </history>
14 ''' -----------------------------------------------------------------------------
15 Public Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
16 Dim i As Int32
17 Dim max As Int32
18
19 For i = 0 To list.Length - 1
20 If list(i) > max Then
21 max = list(i)
22 End If
23 Next
24
25 Return max
26 End Function
27
28 End Class
然后编写测试类:
1
Imports
NUnit.Framework
2
3 <TestFixture()> _
4 Public Class Class1Test Class Class1Test
5
6 ''' -----------------------------------------------------------------------------
7 ''' <summary>
8 ''' 测试 Class1 类的 FindMax 方法
9 ''' </summary>
10 ''' <remarks>
11 ''' </remarks>
12 ''' <history>
13 ''' [Tony] 2006-4-20 Created
14 ''' </history>
15 ''' -----------------------------------------------------------------------------
16 <Test()> _
17 Public Sub FindMaxTest() Sub FindMaxTest()
18 ' 定义一个数组
19 Dim list1 As Int32() = {1, 3, 10, 4}
20
21 Dim my As New Class1
22 ' 测试数组 list1 中的最大整数是不是 10 。
23 Assert.AreEqual(10, my.FindMax(list1))
24 End Sub
25 End Class
2
3 <TestFixture()> _
4 Public Class Class1Test Class Class1Test
5
6 ''' -----------------------------------------------------------------------------
7 ''' <summary>
8 ''' 测试 Class1 类的 FindMax 方法
9 ''' </summary>
10 ''' <remarks>
11 ''' </remarks>
12 ''' <history>
13 ''' [Tony] 2006-4-20 Created
14 ''' </history>
15 ''' -----------------------------------------------------------------------------
16 <Test()> _
17 Public Sub FindMaxTest() Sub FindMaxTest()
18 ' 定义一个数组
19 Dim list1 As Int32() = {1, 3, 10, 4}
20
21 Dim my As New Class1
22 ' 测试数组 list1 中的最大整数是不是 10 。
23 Assert.AreEqual(10, my.FindMax(list1))
24 End Sub
25 End Class
运行 NUnit ,
按 Run 运行 NUnit :
测试通过了,但我的测试类里面仅仅判断了正数的数组,我们还必须做更完整的单元测试,比如测试负数,边界测试等。
下面是更新过的测试类:
1
Imports
NUnit.Framework
2
3 <TestFixture()> _
4 Public Class Class1Test Class Class1Test
5
6 ''' -----------------------------------------------------------------------------
7 ''' <summary>
8 ''' 测试 Class1 类的 FindMax 方法
9 ''' </summary>
10 ''' <remarks>
11 ''' </remarks>
12 ''' <history>
13 ''' [Tony] 2006-4-20 Created
14 ''' </history>
15 ''' -----------------------------------------------------------------------------
16 <Test()> _
17 Public Sub FindMaxTest() Sub FindMaxTest()
18 ' 定义一个数组
19 Dim list1() As Int32 = {1, 3, 10, 4}
20 Dim list2() As Int32 = {1, 3, 4, 10}
21 Dim list3() As Int32 = {10, 3, 1, 4}
22 Dim list4() As Int32 = {-2, -1, -3}
23
24 Dim my As New Class1
25 ' 测试数组 list1 中的最大整数是不是 10 。
26 Assert.AreEqual(10, my.FindMax(list1))
27
28 ' 测试边界值
29 Assert.AreEqual(10, my.FindMax(list2))
30 Assert.AreEqual(10, my.FindMax(list3))
31
32 ' 测试负数数组,数组中最大值应该是- 1
33 Assert.AreEqual(-1, my.FindMax(list4))
34
35 End Sub
36 End Class
2
3 <TestFixture()> _
4 Public Class Class1Test Class Class1Test
5
6 ''' -----------------------------------------------------------------------------
7 ''' <summary>
8 ''' 测试 Class1 类的 FindMax 方法
9 ''' </summary>
10 ''' <remarks>
11 ''' </remarks>
12 ''' <history>
13 ''' [Tony] 2006-4-20 Created
14 ''' </history>
15 ''' -----------------------------------------------------------------------------
16 <Test()> _
17 Public Sub FindMaxTest() Sub FindMaxTest()
18 ' 定义一个数组
19 Dim list1() As Int32 = {1, 3, 10, 4}
20 Dim list2() As Int32 = {1, 3, 4, 10}
21 Dim list3() As Int32 = {10, 3, 1, 4}
22 Dim list4() As Int32 = {-2, -1, -3}
23
24 Dim my As New Class1
25 ' 测试数组 list1 中的最大整数是不是 10 。
26 Assert.AreEqual(10, my.FindMax(list1))
27
28 ' 测试边界值
29 Assert.AreEqual(10, my.FindMax(list2))
30 Assert.AreEqual(10, my.FindMax(list3))
31
32 ' 测试负数数组,数组中最大值应该是- 1
33 Assert.AreEqual(-1, my.FindMax(list4))
34
35 End Sub
36 End Class
重新运行 NUnit ,如下:
哦? 31 行出错:
Assert.AreEqual(-1, my.FindMax(list4))
期望值是- 1 ,但实际却是 0 ,我们回头看一下代码,很容易发现,原来是
Dim max As Int32
这里出错了, max 的初始值就是 0 ,所以后面循环判断最大值,对于负数来说,是错误的,重新修改代码:
1
Public
Class Class1
Class
Class1
2 ''' -----------------------------------------------------------------------------
3 ''' <summary>
4 ''' 查找最大值
5 ''' </summary>
6 ''' <param name="list"> 传入整数数组 </param>
7 ''' <returns> 返回数组中的最大值 </returns>
8 ''' <remarks>
9 ''' </remarks>
10 ''' <history>
11 ''' [Tony] 2006-4-20 Created
12 ''' </history>
13 ''' -----------------------------------------------------------------------------
14 Public Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
15 Dim i As Int32
16 Dim max As Int32 = Int32.MinValue
17
18 For i = 0 To list.Length - 1
19 If list(i) > max Then
20 max = list(i)
21 End If
22 Next
23
24 Return max
25 End Function
26
27 End Class
2 ''' -----------------------------------------------------------------------------
3 ''' <summary>
4 ''' 查找最大值
5 ''' </summary>
6 ''' <param name="list"> 传入整数数组 </param>
7 ''' <returns> 返回数组中的最大值 </returns>
8 ''' <remarks>
9 ''' </remarks>
10 ''' <history>
11 ''' [Tony] 2006-4-20 Created
12 ''' </history>
13 ''' -----------------------------------------------------------------------------
14 Public Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
15 Dim i As Int32
16 Dim max As Int32 = Int32.MinValue
17
18 For i = 0 To list.Length - 1
19 If list(i) > max Then
20 max = list(i)
21 End If
22 Next
23
24 Return max
25 End Function
26
27 End Class
再运行 NUnit ,这次终于正确了。
冲这个例子可以看出,单元测试能帮我们发现一些比较难以发现的 bug 。
下一篇,我再具体写一些 NUnit 的使用方法。
这篇学习笔记主要解释一下
“NUnit
学习笔记
1”
中举的例子,说明一下
NUnit
的主要用法。
上个例子中,主要结构如下:
其中 Class1 内包含了求最大值的方法,也是我要测试的类。
Class1Test 就是用来测试 Class1 中方法的测试类。
流程:
1 ,要使用 NUnit ,先必须添加 nunit.framework 引用:
在 Solution Explorer 中的 References 上按右键,添加引用,然后按 browse ,在 NUnit 目录下找到 nunit.framework.dll ,添加
2 ,在测试类 Class1Test 的头上添加 Imports NUnit.Framework ; c# 是 using NUnit.Framework;
3 ,标示测试类,在测试类上添加 <TestFixture()> 这个 Attribute ,然后添加一个无参的构造函数( c# 为必须, vb.net 不必须),如下:
上个例子中,主要结构如下:
其中 Class1 内包含了求最大值的方法,也是我要测试的类。
Class1Test 就是用来测试 Class1 中方法的测试类。
流程:
1 ,要使用 NUnit ,先必须添加 nunit.framework 引用:
在 Solution Explorer 中的 References 上按右键,添加引用,然后按 browse ,在 NUnit 目录下找到 nunit.framework.dll ,添加
2 ,在测试类 Class1Test 的头上添加 Imports NUnit.Framework ; c# 是 using NUnit.Framework;
3 ,标示测试类,在测试类上添加 <TestFixture()> 这个 Attribute ,然后添加一个无参的构造函数( c# 为必须, vb.net 不必须),如下:
1
Imports
NUnit.Framework
2
3 <TestFixture()> _
4 Public Class Class1Test
5 Public Sub New ()
6
7 End Sub
8
9 End Class
2
3 <TestFixture()> _
4 Public Class Class1Test
5 Public Sub New ()
6
7 End Sub
8
9 End Class
4 ,然后就可以添加一个测试方法了,测试方法前面加上 <test()> 的 Attribute
1
<Test()> _
2 Public Sub FindMaxTest()
3 ' 定义一个数组
4 Dim list1 As Int32() = {1, 3, 10, 4}
5
6 Dim my As New Class1
7 ' 测试数组 list1 中的最大整数是不是 10 。
8 Assert.AreEqual(4, my.FindMax(list1))
9 End Sub
2 Public Sub FindMaxTest()
3 ' 定义一个数组
4 Dim list1 As Int32() = {1, 3, 10, 4}
5
6 Dim my As New Class1
7 ' 测试数组 list1 中的最大整数是不是 10 。
8 Assert.AreEqual(4, my.FindMax(list1))
9 End Sub
其中,
Assert.AreEqual
()就是
NUnit
提供的一个断言,用来判断前后
2
个值是否相等。如果相等,则测试通过,否则测试失败。
5
,如此,一个单元测试就算是写好了,可以使用了(当然,测试用例还不够完善
)
。
接下去运行这个单元测试:先编译 solution ,生成一个 exe 或 dll 的程序集,打开 nunit-gui.exe ,点 “file 。。。 ”---- 〉 “Open 。。。 ” ,然后,选中刚才生成的程序集,出现如下图:
6 ,然后按 Run ,就可以进行测试了,如下图:
出现一个大大的红色, NUnit 里面,红色代码 test 失败,绿色代表成功,黄色代码忽略。
这里出现红色错误,是由于我故意在测试函数里面写错的:
Assert.AreEqual(4, my.FindMax(list1))
这里的最大值,应该是 10 ,测试函数改成如下代码:
接下去运行这个单元测试:先编译 solution ,生成一个 exe 或 dll 的程序集,打开 nunit-gui.exe ,点 “file 。。。 ”---- 〉 “Open 。。。 ” ,然后,选中刚才生成的程序集,出现如下图:
6 ,然后按 Run ,就可以进行测试了,如下图:
出现一个大大的红色, NUnit 里面,红色代码 test 失败,绿色代表成功,黄色代码忽略。
这里出现红色错误,是由于我故意在测试函数里面写错的:
Assert.AreEqual(4, my.FindMax(list1))
这里的最大值,应该是 10 ,测试函数改成如下代码:
1
<Test()> _
2 Public Sub FindMaxTest()
3 ' 定义一个数组
4 Dim list1 As Int32() = {1, 3, 10, 4}
5
6 Dim my As New Class1
7 ' 测试数组 list1 中的最大整数是不是 10 。
8 Assert.AreEqual(10, my.FindMax(list1))
9 End Sub
2 Public Sub FindMaxTest()
3 ' 定义一个数组
4 Dim list1 As Int32() = {1, 3, 10, 4}
5
6 Dim my As New Class1
7 ' 测试数组 list1 中的最大整数是不是 10 。
8 Assert.AreEqual(10, my.FindMax(list1))
9 End Sub
重新编译 solution , NUnit 不必重起,它会自动装载最新的程序集,再按 NUnit 的 Run ,如下图:
7
,然后,让我们完善一下我们的测试函数:
1
<Test()> _
2 Public Sub FindMaxTest() Sub FindMaxTest()
3 ' 定义一个数组
4 Dim list1() As Int32 = {1, 3, 10, 4}
5 Dim list2() As Int32 = {1, 3, 4, 10}
6 Dim list3() As Int32 = {10, 3, 1, 4}
7 Dim list4() As Int32 = {-2, -1, -3}
8
9 Dim my As New Class1
10 ' 测试数组 list1 中的最大整数是不是 10 。
11 Assert.AreEqual(10, my.FindMax(list1))
12
13 ' 测试边界值
14 Assert.AreEqual(10, my.FindMax(list2))
15 Assert.AreEqual(10, my.FindMax(list3))
16
17 ' 测试负数数组,数组中最大值应该是- 1
18 Assert.AreEqual(-1, my.FindMax(list4))
19
20 End Sub
2 Public Sub FindMaxTest() Sub FindMaxTest()
3 ' 定义一个数组
4 Dim list1() As Int32 = {1, 3, 10, 4}
5 Dim list2() As Int32 = {1, 3, 4, 10}
6 Dim list3() As Int32 = {10, 3, 1, 4}
7 Dim list4() As Int32 = {-2, -1, -3}
8
9 Dim my As New Class1
10 ' 测试数组 list1 中的最大整数是不是 10 。
11 Assert.AreEqual(10, my.FindMax(list1))
12
13 ' 测试边界值
14 Assert.AreEqual(10, my.FindMax(list2))
15 Assert.AreEqual(10, my.FindMax(list3))
16
17 ' 测试负数数组,数组中最大值应该是- 1
18 Assert.AreEqual(-1, my.FindMax(list4))
19
20 End Sub
新增加了 3 个断言,用来测试边界值,负数。
8 , Run ,如下图:
哈哈,还是绿灯阿,我们的求最大数的方法就大致测试完成了。
下面列出一下常用的断言:
常用的 NUnit 断言有:
method
|
usage
|
example
|
Assert.AreEqual(object expected, object actual[, string message])
|
验证两个对象是否相等
|
Assert.AreEqual(2, 1+1)
|
Assert.AreSame(object expected, object actual[, string message])
|
验证两个引用是否指向同意对象
|
object expected = new object();
object actual = expected;
Assert.AreSame(expected, actual)
|
Assert.IsFalse(bool)
|
验证bool值是否为false
|
Assert.IsFalse(false)
|
Assert.IsTrue(bool)
|
验证bool值是否为true
|
Assert.IsTrue(true)
|
Assert.IsNotNull(object)
|
验证对象是否不为null
|
Assert.IsNotNull(new object())
|
Assert.IsNull(object)
|
验证对象是否为null
|
Assert.IsNull(null);
|
本章主要讲解
NUnit
的几个
Attribute
(特性)的用法。
1 , TestFixture
1 , TestFixture
Imports
NUnit.Framework
<TestFixture()> _
Public Class Class1Test Class Class1Test
Public Sub New() Sub New ()
End Sub
end class
<TestFixture()> _
Public Class Class1Test Class Class1Test
Public Sub New() Sub New ()
End Sub
end class
上面代码中的
<TestFixture()>
就是一个特性
(C#
中使用
[TestFixture]),
这个特性告诉
NUnit
:
这个类包含了测试代码 , 你需要给我看一下。然后 NUnit 就到这个类里面去看看是否有需要他出马的机会。
2,Test
这个类包含了测试代码 , 你需要给我看一下。然后 NUnit 就到这个类里面去看看是否有需要他出马的机会。
2,Test
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
' 定义一个数组
Dim list1 As Int32() = {1, 3, 10, 4}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(4, my.FindMax(list1))
End Sub
Public Sub FindMaxTest() Sub FindMaxTest()
' 定义一个数组
Dim list1 As Int32() = {1, 3, 10, 4}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(4, my.FindMax(list1))
End Sub
这里的
<Test()>
(
C#
中为
[Test]),
这个特性告诉
NUnit
:
这是一个需要测试的方法,你给我测试一下,并用颜色告诉我结果(红色说明测试失败,绿色说明测试成功)。
对应到 NUnit 的 gui 中如下图:
图中左边那个灰色的圆点( FindMaxTest )就是由 Test 特性标示出来的一个需要测试的方法,然后我们可以通过按 “Run” 来运行这个测试, NUnit 将通过颜色来返回。
这是 NUnit 最主要的 2 个 Attribute ,有了这 2 个,就可以编写单元测试了。
除了这 2 个 Attribute 之外,还有一些其他的 Attribute ,可以提供给我们更强大的功能,下面列出一些常用的:
这是一个需要测试的方法,你给我测试一下,并用颜色告诉我结果(红色说明测试失败,绿色说明测试成功)。
对应到 NUnit 的 gui 中如下图:
图中左边那个灰色的圆点( FindMaxTest )就是由 Test 特性标示出来的一个需要测试的方法,然后我们可以通过按 “Run” 来运行这个测试, NUnit 将通过颜色来返回。
这是 NUnit 最主要的 2 个 Attribute ,有了这 2 个,就可以编写单元测试了。
除了这 2 个 Attribute 之外,还有一些其他的 Attribute ,可以提供给我们更强大的功能,下面列出一些常用的:
标识测试类
|
TestFixture
|
标识测试方法
|
Test
|
标识测试类初始化函数
|
TestFixtureSetup
|
标识测试类资源释放函数
|
TestFixtureTearDown
|
标识测试用例初始化函数
|
Setup
|
标识测试用例资源释放函数
|
TearDown
|
标识忽略该测试方法
|
Ignore
|
标识该用例所期望抛出的异常
|
ExpectedException
|
标识测试用例的分类
|
Category
|
让我们接下去讲解其他 Attribute:
3,TestFixtureSetup 和 TestFixtureTearDown
TestFixtureSetup 这个特性的作用是为整个测试类初始化一些资源,准备好测试环境,然后给该测试类的几个测试( Test )使用,而 TestFixtureTearDown 则是把 TestFixtureSetup 初始化的一些资源释放掉。
我们可以通过下面这个例子来更好的理解:
Imports
NUnit.Framework
<TestFixture()> _
Public Class Class1Test Class Class1Test
Private con As Connection
<TestFixtureSetUp()> _
Public Sub MyFixtureSetUp() Sub MyFixtureSetUp()
' 打开数据库联接
conn = New Connection("sqlXXX", user, password)
conn.open()
End Sub
<TestFixtureTearDown()> _
Public Sub MyFixtureTearDown() Sub MyFixtureTearDown()
' 关闭数据库联接
conn.close()
End Sub
<Test()> _
Public Sub Mytest1() Sub Mytest1()
' 使用 conn 作某些测试
End Sub
<Test()> _
Public Sub Mytest2() Sub Mytest2()
' 使用 conn 作某些测试
End Sub
End Class
<TestFixture()> _
Public Class Class1Test Class Class1Test
Private con As Connection
<TestFixtureSetUp()> _
Public Sub MyFixtureSetUp() Sub MyFixtureSetUp()
' 打开数据库联接
conn = New Connection("sqlXXX", user, password)
conn.open()
End Sub
<TestFixtureTearDown()> _
Public Sub MyFixtureTearDown() Sub MyFixtureTearDown()
' 关闭数据库联接
conn.close()
End Sub
<Test()> _
Public Sub Mytest1() Sub Mytest1()
' 使用 conn 作某些测试
End Sub
<Test()> _
Public Sub Mytest2() Sub Mytest2()
' 使用 conn 作某些测试
End Sub
End Class
当你用 NUnit 测试 Mytest1 , Mytest2 这 2 个 test 时,程序的运行顺序是这样的:
MyFixtureSetUp (初始化测试环境)
Mytest1 ( test1 )
Mytest2 ( test2 )
TestFixtureTearDown (释放资源)
4,Setup 和 TearDown
这 2 个特性和 TestFixtureSetup , TestFixtureTearDown 有点类似,区别在于:
Setup 将在每个 test 之前运行, TearDown 将在每个 test 之后运行。简单的说 TestFixtureSetup , TestFixtureTearDown 在一个测试类中之会运行一次;而 Setup 和 TearDown ,这个测试类有几个 test 被测试,就将运行几次。
举例说明:
Imports
NUnit.Framework
<TestFixture()> _
Public Class Class1Test Class Class1Test
Private con As Connection
<SetUp()> _
Public Sub MyFixtureSetUp() Sub MyFixtureSetUp()
' 打开数据库联接
conn = New Connection("sqlXXX", user, password)
conn.open()
End Sub
<TearDown()> _
Public Sub MyFixtureTearDown() Sub MyFixtureTearDown()
' 关闭数据库联接
conn.close()
End Sub
<Test()> _
Public Sub Mytest1() Sub Mytest1()
' 使用 conn 作某些测试
End Sub
<Test()> _
Public Sub Mytest2() Sub Mytest2()
' 使用 conn 作某些测试
End Sub
End Class
<TestFixture()> _
Public Class Class1Test Class Class1Test
Private con As Connection
<SetUp()> _
Public Sub MyFixtureSetUp() Sub MyFixtureSetUp()
' 打开数据库联接
conn = New Connection("sqlXXX", user, password)
conn.open()
End Sub
<TearDown()> _
Public Sub MyFixtureTearDown() Sub MyFixtureTearDown()
' 关闭数据库联接
conn.close()
End Sub
<Test()> _
Public Sub Mytest1() Sub Mytest1()
' 使用 conn 作某些测试
End Sub
<Test()> _
Public Sub Mytest2() Sub Mytest2()
' 使用 conn 作某些测试
End Sub
End Class
当你用 NUnit 测试 Mytest1 , Mytest2 这 2 个 test 时,程序的运行顺序是这样的:
SetUp (初始化测试环境)
Mytest1 ( test1 )
TearDown (释放资源)
SetUp (初始化测试环境)
Mytest2 ( test2 )
TearDown (释放资源)
可以看出,每个 test 前后都运行了 SetUp 和 TearDown
对 3 和 4 这 2 组特性的选择,我个人在实际使用中感觉差别不大,随便用哪种都行, 2 种都用也无不可。我一般是用 TestFixtureSetup 和 TestFixtureTearDown ,一次性把资源都设置好,然后再一次性释放,写起来方便
5 , Ignore
临时忽略一些 test 。
在以下情况可能会用到:
( 1 ),你的测试用例写好了,但实际代码却还没完成,这样的话测试肯定是不能通过的,但是你又不想看到 NUnit 抛出一个红灯笼,你就可以暂时用 Ignore 忽略掉这个 test 。 NUnit 会抛出一个黄灯,提醒你这个测试被忽略了。(不过,抛出个红灯笼也有好处的,它能鞭策你快点写好代码,哈哈)
( 2 ),有些测试可能耗费非常长的时间(比如几个小时),你展示不想测试它们,而想等半夜再测试,你就可以暂时 Ignore 它们。(不过,推荐用 Category 特性来把这些长时间测试分类出来,而不是用 Ignore ,这个将在后面讲到)
实例说明:
<Test(), Ignore("Not Ready")> _
Public Sub FindMaxTest() Sub FindMaxTest()
' 定义一个数组
Dim list1 As Int32() = {1, 3, 10, 4}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
End Sub
Public Sub FindMaxTest() Sub FindMaxTest()
' 定义一个数组
Dim list1 As Int32() = {1, 3, 10, 4}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
End Sub
(C#
中为
[Test,Ignore("XXX")] )
运行 NUnit ,我们将看到如下结果:
运行 NUnit ,我们将看到如下结果:
6,ExpectedException
标识该用例所期望抛出的异常
有时候我们知道在特定条件下我们的程序将会抛出某个异常,我们就可以用 ExpectedException 这个特性在测试代码中验证,程序是否如我们所想的抛出了这个异常。
如,我们那个求最大值的方法,如果传进去一个空的 int32 数组,应该会抛出一个 NullReferenceException 异常,为了验证我的猜想,我写了如下测试:
标识该用例所期望抛出的异常
有时候我们知道在特定条件下我们的程序将会抛出某个异常,我们就可以用 ExpectedException 这个特性在测试代码中验证,程序是否如我们所想的抛出了这个异常。
如,我们那个求最大值的方法,如果传进去一个空的 int32 数组,应该会抛出一个 NullReferenceException 异常,为了验证我的猜想,我写了如下测试:
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()Sub FindMaxTest() Sub FindMaxTest()
' 定义一个数组
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
<Test(), ExpectedException( GetType (NullReferenceException))> _
Public Sub TestForException() Sub TestForException()
Dim list1() As Int32
Dim my As New Class1
my.FindMax(list1)
End Sub
Public Sub FindMaxTest() Sub FindMaxTest()Sub FindMaxTest() Sub FindMaxTest()
' 定义一个数组
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
<Test(), ExpectedException( GetType (NullReferenceException))> _
Public Sub TestForException() Sub TestForException()
Dim list1() As Int32
Dim my As New Class1
my.FindMax(list1)
End Sub
(C#
中为
[Test,ExpectedException(Typeof(NullReferenceExcepton))] )
运行 NUnit ,如下:
果然如此,程序的确抛出了 NullReferenceException 。而假如系统没有如我们所料抛出异常,或者抛出的不是此类异常, NUnit 则会给我们个红灯笼。
7 , Category
分类。
该特性可以把一些测试分成不同的种类,比如我们前面提到的,假如有些测试很耗时,我们就可以把它们分类成 LongTime 测试,而把其他的测试分类成 ShortTime 测试,然后,我们可以在 NUnit 中选择只运行 ShortTime 的测试,那些 LongTime 的测试则可以在夜晚自动构建的时候运行它们。
使用举例如下:
运行 NUnit ,如下:
果然如此,程序的确抛出了 NullReferenceException 。而假如系统没有如我们所料抛出异常,或者抛出的不是此类异常, NUnit 则会给我们个红灯笼。
7 , Category
分类。
该特性可以把一些测试分成不同的种类,比如我们前面提到的,假如有些测试很耗时,我们就可以把它们分类成 LongTime 测试,而把其他的测试分类成 ShortTime 测试,然后,我们可以在 NUnit 中选择只运行 ShortTime 的测试,那些 LongTime 的测试则可以在夜晚自动构建的时候运行它们。
使用举例如下:
Imports
NUnit.Framework
<TestFixture()> _
Public Class Class1Test Class Class1Test
<Test(), Category("ShortTime")> _
Public Sub Mytest1() Sub Mytest1()
End Sub
<Test(), Category("ShortTime")> _
Public Sub Mytest2() Sub Mytest2()
End Sub
<Test(), Category("LongTime")> _
Public Sub Mytest3() Sub Mytest3()
End Sub
<Test(), Category("LongTime")> _
Public Sub Mytest4() Sub Mytest4()
End Sub
End Class
<TestFixture()> _
Public Class Class1Test Class Class1Test
<Test(), Category("ShortTime")> _
Public Sub Mytest1() Sub Mytest1()
End Sub
<Test(), Category("ShortTime")> _
Public Sub Mytest2() Sub Mytest2()
End Sub
<Test(), Category("LongTime")> _
Public Sub Mytest3() Sub Mytest3()
End Sub
<Test(), Category("LongTime")> _
Public Sub Mytest4() Sub Mytest4()
End Sub
End Class
(C#
中为
[Test][Category
(
“ShortTime”)] )
这个测试类中有 2 种测试方法: ShortTime 和 LongTime ,
运行 NUnit ,选择 "Categories" ,我们将看到, Available Categories 中看到有 2 种分类,选择 “shortTime” ,然后运行,只有 ShortTime 的那些测试方法被运行了。
除了这些 Attribute 之外,其实还有一些,不过我在实际使用中很少用到,我就不拿出来讲了。
下篇学习笔记,我将列举几种单元测试与项目结合的方法。
这个测试类中有 2 种测试方法: ShortTime 和 LongTime ,
运行 NUnit ,选择 "Categories" ,我们将看到, Available Categories 中看到有 2 种分类,选择 “shortTime” ,然后运行,只有 ShortTime 的那些测试方法被运行了。
除了这些 Attribute 之外,其实还有一些,不过我在实际使用中很少用到,我就不拿出来讲了。
下篇学习笔记,我将列举几种单元测试与项目结合的方法。
单元测试要运用到实际项目中去,必须把单元测试代码和项目通过某种途径联系在一起。
比如,在我的学习笔记 1 中,有一个工程: WindowsApplication12 ,这个工程中有 Class1 这个类,该类就是项目的实际代码,随后我在该工程中添加一个 Class1Test 的测试类,用来测试 Class1 中的一些方法。
这个过程,就是一种结合方法:对每个需要测试的类,都在该类的工程下建立一个测试类。
在我的实际经验中,接触到如下几种方法,以下进行举例说明,每种方法都有其特定使用环境,优缺点,供大家参考:
1 ,单元测试代码,直接写在需要被测试的类中。
solution 结构如下:
代码如下:
比如,在我的学习笔记 1 中,有一个工程: WindowsApplication12 ,这个工程中有 Class1 这个类,该类就是项目的实际代码,随后我在该工程中添加一个 Class1Test 的测试类,用来测试 Class1 中的一些方法。
这个过程,就是一种结合方法:对每个需要测试的类,都在该类的工程下建立一个测试类。
在我的实际经验中,接触到如下几种方法,以下进行举例说明,每种方法都有其特定使用环境,优缺点,供大家参考:
1 ,单元测试代码,直接写在需要被测试的类中。
solution 结构如下:
代码如下:
Imports
NUnit.Framework
<TestFixture()> _
Public Class Class1 Class Class1
''' -----------------------------------------------------------------------------
''' <summary>
''' 查找最大值
''' </summary>
''' <param name="list"> 传入整数数组 </param>
''' <returns> 返回数组中的最大值 </returns>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
Dim i As Int32
Dim max As Int32 = Int32.MinValue
For i = 0 To list.Length - 1
If list(i) > max Then
max = list(i)
End If
Next
Return max
End Function
''' -----------------------------------------------------------------------------
''' <summary>
''' 测试 Class1 类的 FindMax 方法
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
'
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
End Class
<TestFixture()> _
Public Class Class1 Class Class1
''' -----------------------------------------------------------------------------
''' <summary>
''' 查找最大值
''' </summary>
''' <param name="list"> 传入整数数组 </param>
''' <returns> 返回数组中的最大值 </returns>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
Dim i As Int32
Dim max As Int32 = Int32.MinValue
For i = 0 To list.Length - 1
If list(i) > max Then
max = list(i)
End If
Next
Return max
End Function
''' -----------------------------------------------------------------------------
''' <summary>
''' 测试 Class1 类的 FindMax 方法
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
'
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
End Class
运行 Nunit ,结果如下:
这种方法的优点很明显:由于测试代码同被测试的方法放在一个类中,所以 private 等方法很容易被测试。但同时缺点也很明显,该类会被写得很复杂,估计很少会有人喜欢看这种代码,而且万一客户不需要这些代码的话,在最后部署的时候,关 del 测试代码,估计也是个大问题。
2 ,每写一个需要被测试的类,就写当前工程下新建一个相应的测试类,名字可以在被测试类后面加上 Test 以示区别。
solution 结构如下:
代码就不写了,大致就是我在笔记 1 , 2 中举的例子。
这种方法的优点是结构比较清晰,在比较小的工程中使用还算不错,修改测试代码也比较方法。缺点同样是部署时删除单元测试代码比较麻烦,同时 solution 太大,有很多 project 时,有很大局限性。
3 , solution 有很多个工程时,专门新增加一些工程,用于写单元测试,比如有一个 ClassLibrary3 工程,则建一个 TestForClassLibrary3 工程,单元测试类放到这个工程中去。
solution 结构如下:
注意,测试工程要引用被测试工程。
代码如下:
Public
Class Class1
Class
Class1
''' -----------------------------------------------------------------------------
''' <summary>
''' 查找最大值
''' </summary>
''' <param name="list"> 传入整数数组 </param>
''' <returns> 返回数组中的最大值 </returns>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
Dim i As Int32
Dim max As Int32 = Int32.MinValue
For i = 0 To list.Length - 1
If list(i) > max Then
max = list(i)
End If
Next
Return max
End Function
End Class
''' -----------------------------------------------------------------------------
''' <summary>
''' 查找最大值
''' </summary>
''' <param name="list"> 传入整数数组 </param>
''' <returns> 返回数组中的最大值 </returns>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
Function FindMax() Function FindMax( ByVal list As Int32()) As Int32
Dim i As Int32
Dim max As Int32 = Int32.MinValue
For i = 0 To list.Length - 1
If list(i) > max Then
max = list(i)
End If
Next
Return max
End Function
End Class
Imports
NUnit.Framework
Imports ClassLibrary3
<TestFixture()> _
Public Class Class1Test Class Class1Test
Public Sub New() Sub New ()
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' 测试 Class1 类的 FindMax 方法
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
'
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
End Class
Imports ClassLibrary3
<TestFixture()> _
Public Class Class1Test Class Class1Test
Public Sub New() Sub New ()
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' 测试 Class1 类的 FindMax 方法
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
'
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
End Class
由于是以工程为单位,所以部署起来很容易,只要把这几个工程去掉就可以了,将来再要用,也只要加上就可以了。不过操作相对来说比较繁琐,没有前
2
种方法便捷。
4 ,以上 3 种方法都需要在项目的 solution 中增加东西,但如果你的项目不允许你增加任何测试类或工程(虽然感觉很愚蠢,但的确很多公司不允许程序员这么做),或者你根本没有权限增加工程或文件,这 3 种方法将都不能使用,这时可以用第 4 种方法。
比如你想测试 ClassLibrary3 工程下的 Class1 类,你可以先 build 你的项目,生成 ClassLibrary3 工程的 dll 文件,然后在你本地建一个测试工程,引用这个 dll ,就可以不需要修改你的项目了。
测试 solution 结构如下(这个 solution 是在你电脑本地的,与你的项目没有关系):
测试代码如下:
4 ,以上 3 种方法都需要在项目的 solution 中增加东西,但如果你的项目不允许你增加任何测试类或工程(虽然感觉很愚蠢,但的确很多公司不允许程序员这么做),或者你根本没有权限增加工程或文件,这 3 种方法将都不能使用,这时可以用第 4 种方法。
比如你想测试 ClassLibrary3 工程下的 Class1 类,你可以先 build 你的项目,生成 ClassLibrary3 工程的 dll 文件,然后在你本地建一个测试工程,引用这个 dll ,就可以不需要修改你的项目了。
测试 solution 结构如下(这个 solution 是在你电脑本地的,与你的项目没有关系):
测试代码如下:
Imports
NUnit.Framework
<TestFixture()> _
Public Class Class1Test Class Class1Test
Public Sub New() Sub New ()
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' 测试 Class1 类的 FindMax 方法
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
'
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
End Class
<TestFixture()> _
Public Class Class1Test Class Class1Test
Public Sub New() Sub New ()
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' 测试 Class1 类的 FindMax 方法
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [TonyGong] 5/25/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
<Test()> _
Public Sub FindMaxTest() Sub FindMaxTest()
'
Dim list1() As Int32 = {1, 3, 10, 4}
Dim list2() As Int32 = {1, 3, 4, 10}
Dim list3() As Int32 = {10, 3, 1, 4}
Dim list4() As Int32 = {-2, -1, -3}
Dim my As New Class1
' 测试数组 list1 中的最大整数是不是 10 。
Assert.AreEqual(10, my.FindMax(list1))
' 测试边界值
Assert.AreEqual(10, my.FindMax(list2))
Assert.AreEqual(10, my.FindMax(list3))
' 测试负数数组,数组中最大值应该是- 1
Assert.AreEqual(-1, my.FindMax(list4))
End Sub
End Class
这种方法的最大优点是不需要修改你的项目,不过缺点也很多,不够灵活,操作复杂等。
我个人比较多用 2 , 3 ,在很小的模块中有时会用 1 ,不过比起用 1 来,可能使用 TestDriven.NET 更加方便些,这个我打算后面单独写篇文章。
下面简单介绍一下上边用到的静态类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()方法,用来比较两个字符串是否相等。
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()方法,用来比较两个字符串是否相等。