NUnit学习笔记

最近一段时间在研究单元测试,先记录一下学习记录吧。

首先,单元测试的目的,我觉得最主要有以下几点:
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

然后编写测试类:
 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

运行 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

重新运行 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


再运行 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 不必须),如下:
1  Imports  NUnit.Framework
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
其中, Assert.AreEqual ()就是 NUnit 提供的一个断言,用来判断前后 2 个值是否相等。如果相等,则测试通过,否则测试失败。
5 ,如此,一个单元测试就算是写好了,可以使用了(当然,测试用例还不够完善 )
接下去运行这个单元测试:先编译 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

重新编译 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

新增加了 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
Imports  NUnit.Framework

<TestFixture()> _
Public  Class Class1Test Class  Class1Test
    
Public  Sub New() Sub  New ()

    
End Sub
end class
上面代码中的 <TestFixture()> 就是一个特性 (C# 中使用 [TestFixture]), 这个特性告诉 NUnit
这个类包含了测试代码 , 你需要给我看一下。然后 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
这里的 <Test()> C# 中为 [Test]), 这个特性告诉 NUnit
这是一个需要测试的方法,你给我测试一下,并用颜色告诉我结果(红色说明测试失败,绿色说明测试成功)。
对应到 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

当你用 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

当你用 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
(C# 中为 [Test,Ignore("XXX")]           )
运行 NUnit ,我们将看到如下结果:
 
6,ExpectedException
标识该用例所期望抛出的异常
有时候我们知道在特定条件下我们的程序将会抛出某个异常,我们就可以用 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

(C# 中为 [Test,ExpectedException(Typeof(NullReferenceExcepton))]        )
运行 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
(C# 中为 [Test][Category “ShortTime”)]        )
这个测试类中有 2 种测试方法: ShortTime LongTime
运行 NUnit ,选择 "Categories" ,我们将看到, Available Categories 中看到有 2 种分类,选择 “shortTime” ,然后运行,只有 ShortTime 的那些测试方法被运行了。



除了这些 Attribute 之外,其实还有一些,不过我在实际使用中很少用到,我就不拿出来讲了。

下篇学习笔记,我将列举几种单元测试与项目结合的方法。
单元测试要运用到实际项目中去,必须把单元测试代码和项目通过某种途径联系在一起。
比如,在我的学习笔记 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


运行 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

 
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
 
由于是以工程为单位,所以部署起来很容易,只要把这几个工程去掉就可以了,将来再要用,也只要加上就可以了。不过操作相对来说比较繁琐,没有前 2 种方法便捷。

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


这种方法的最大优点是不需要修改你的项目,不过缺点也很多,不够灵活,操作复杂等。

我个人比较多用 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()方法,用来比较两个字符串是否相等。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值