NUnit是一個(gè)專(zhuān)門(mén)針對(duì)于.NET來(lái)寫(xiě)的單元測(cè)試框架,它是xUnit體系中的一員,在xUnit體系中還有針對(duì)Java的JUnit和針對(duì)C++的CPPUnit,在開(kāi)始的時(shí)候NUnit和xUnit體系中的大多數(shù)的做法一樣,僅僅是將Smalltalk或者Java版本轉(zhuǎn)換而來(lái),但是在.NET2.0之后它加入了一些特有的做法。NUnit的官方網(wǎng)站是:http://www.nunit.org/,目前的新版本是:2.6.2。
NUnit下載與安裝
NUnit的每個(gè)版本都提供了兩種形式的下載:安裝文件和免安裝方式,分別是*.msi格式和*.zip格式。前者需要安裝才能使用,并且會(huì)在安裝過(guò)程中創(chuàng)建一些快捷方式和注冊(cè)NUnit的dll到GAC,這樣以后編寫(xiě)NUnit測(cè)試類(lèi)的時(shí)候添加NUnit的dll像添加.Net Framework的dll一樣。如果是下載的zip格式的文件,則不會(huì)創(chuàng)建快捷方式和注冊(cè)dll,在編寫(xiě)單元測(cè)試類(lèi)時(shí)需要手動(dòng)指定NUnit的dll的路徑。
NUnit的運(yùn)行有三種方式:命令行和圖形用戶(hù)界面。以周公當(dāng)前電腦上安裝的NUnit2.5.10為例,安裝路徑為:C:Program Files (x86)NUnit 2.5.10,其下有三個(gè)目錄:bin、doc和samples。在doc目錄下是軟件的文檔(英文),在samples目錄下則是一些樣例代碼。如果是采用免安裝模式的話(huà),運(yùn)行NUnit需要運(yùn)行bin目錄下的文件,在bin目錄下有net-1.1和net-2.0兩個(gè)文件夾,分別對(duì)應(yīng).net的不同版本。
下面介紹如何以不同的方式啟動(dòng)NUnit:
命令行模式:運(yùn)行nunit-console.exe。
圖形用戶(hù)界面模式:運(yùn)行nunit.exe。
并行(parallel)模式:運(yùn)行pnunit-launcher.exe。
注意:.Net2.0版本的NUnit是使用/platform:anycpu參數(shù)來(lái)編譯的,我們知道這樣的結(jié)果是運(yùn)行在x86的系統(tǒng)上會(huì)被JIT編譯成32位的程序,而在x64的系統(tǒng)上會(huì)被JIT編譯成64位的程序。如果使用NUnit在x64系統(tǒng)上測(cè)試32位的程序會(huì)帶來(lái)問(wèn)題。為了避免這個(gè)問(wèn)題,可以使用nunit-agent-x86.exe/nunit-x86.exe來(lái)測(cè)試,因?yàn)樵诰幾g的時(shí)候使用了/platform:x86作為編譯參數(shù)。
下圖是運(yùn)行NUnit的GUI界面:
NUnit的常用Attribute標(biāo)記
這些都是可以用來(lái)作為類(lèi)或者方法的屬性,它們都是System.Attribute類(lèi)的直接或間接子類(lèi),有如下:
Category:用來(lái)將測(cè)試分類(lèi)。這個(gè)在主界面可以看到Tests/Categories兩個(gè)選項(xiàng)卡,如果給方法標(biāo)記了Category屬性會(huì)在Categories選項(xiàng)卡中看得到。
Combinatorial:用來(lái)將來(lái)測(cè)試時(shí)需要測(cè)試各種可能的組合,比如如下代碼:
[csharp] view plaincopy
[Test, Combinatorial]
public void MyTest(
[Values(1, 2, 3)] int x,
[Values("A", "B")] string s)
{
string value = x + s;
Assert.Greater(2, value.Length);
}
測(cè)試時(shí)實(shí)際會(huì)測(cè)試6種情況:MyTest(1, "A")/MyTest(1, "B")/MyTest(2, "A")/MyTest(2, "B")/MyTest(3, "A")/MyTest(3, "B")。
Culture:設(shè)置測(cè)試時(shí)的語(yǔ)言環(huán)境,這對(duì)我們測(cè)試一些語(yǔ)言敏感的場(chǎng)景下有用,比如DateTime.ToString()在不同語(yǔ)言環(huán)境下得到的字符串并不相同。
Description:用于指定測(cè)試對(duì)應(yīng)的描述,如果選擇將測(cè)試結(jié)果生成XML文件,那么會(huì)在XML文件中看到這些描述。
ExpectedException:指出執(zhí)行測(cè)試時(shí)將會(huì)拋出Exception。
Explicit:如果測(cè)試的類(lèi)或者方法使用此Attribute,那么在使用帶GUI的NUnit測(cè)試時(shí)這個(gè)類(lèi)或者方法必須在界面上選定才會(huì)被執(zhí)行。
Explicit:忽略某個(gè)測(cè)試類(lèi)或者方法。
Maxtime:測(cè)試方法大執(zhí)行的毫秒數(shù),如果程序的執(zhí)行時(shí)間超過(guò)指定數(shù)值,那么會(huì)被認(rèn)為測(cè)試失敗。
Random:用于指定如何隨機(jī)生成參數(shù)來(lái)測(cè)試方法。如下面的代碼:
[csharp] view plaincopy
[Test]
public void TestDemo1(
[Values(1, 2, 3)] int x,
[Random(-10,10,2)] int y)
{
Assert.Greater(x + y, 0);
}
表示方法TestDemo1會(huì)生成6個(gè)測(cè)試,1,2,3分別作為參數(shù)x的值與兩次從-10到10之間的隨機(jī)數(shù)y組成6次測(cè)試。
Range:指定參數(shù)的方法,如下面的方法:
[Test]
public void TestDemo2(
[Range(0, 11, 4)] int x)
{
Assert.AreEqual(x%3,0);
}
表示從0開(kāi)始遞增,步長(zhǎng)為4,且不大于11。
Repeat:將重復(fù)測(cè)試的次數(shù)。
RequiresMTA:表示測(cè)試時(shí)需要多線(xiàn)程單元(multi-threaded apartment)。
RequiresSTA:表示測(cè)試時(shí)需要單線(xiàn)程單元(single-threaded apartment)。
SetUp:在每個(gè)測(cè)試方法開(kāi)始之前執(zhí)行的初始化操作。在NUnit 2.5之前要求每個(gè)類(lèi)只能有一個(gè)帶SetUp屬性的實(shí)例方法,但在NUnit 2.5之后則沒(méi)有次數(shù)和必須是實(shí)例方法的限制。
TearDown:與SetUp的作用相反,是在每個(gè)測(cè)試方法執(zhí)行結(jié)束之后執(zhí)行的方法。在NUnit 2.5之前要求每個(gè)類(lèi)只能有一個(gè)帶SetUp屬性的實(shí)例方法,但在NUnit 2.5之后則沒(méi)有次數(shù)和必須是實(shí)例方法的限制。
Test:用來(lái)標(biāo)記需要測(cè)試的方法,在NUnit 2.5之前只能用于標(biāo)記實(shí)例方法,在NUnit 2.5之后則可以用于標(biāo)記靜態(tài)方法。
TestCase:標(biāo)記方法具有參數(shù)并且提供了在測(cè)試時(shí)需要的參數(shù)。如下面的代碼:
[TestCase(12, 3, 4)]
[TestCase(12, 2, 6)]
[TestCase(12, 4, 3)]
public void DivideTest(int n, int d, int q)
{
Assert.AreEqual(q, n / d);
}
將會(huì)執(zhí)行三次測(cè)試,相當(dāng)于:
[Test]
public void DivideTest()
{
Assert.AreEqual(4,12/3);
}
[Test]
public void DivideTest()
{
Assert.AreEqual(6,12/2);
}
[Test]
public void DivideTest()
{
Assert.AreEqual(3,12/4);
}
TestFixture:標(biāo)記一個(gè)類(lèi)可能具有[Test]/[SetUp]/[TearDown]方法,但這個(gè)類(lèi)不能是抽象類(lèi)。
TestFixtureSetUp:標(biāo)記在類(lèi)中所有測(cè)試方法執(zhí)行之前執(zhí)行的方法。在NUnit 2.5之前只能在類(lèi)中將此標(biāo)記多使用于一個(gè)實(shí)例方法,在NUnit 2.5之后則可以標(biāo)記多個(gè)方法,而且不限于實(shí)例方法還可以用于靜態(tài)方法。