1 準備TestDriven和NUnit
單元測試對於程序員來說基本是一個必備的技能。“千里之堤,潰於蟻穴”這句話對於程序員也適用。記得一位大牛說過“笨蛋都能寫出讓機器看懂的程序,真正的聰明人寫出讓人看得懂的程序”。單元測試能顯著提高自己程序的質量,當項目變得很大的時候,良好的單元測試也能提高項目的質量,當然,它也能讓人充滿成就感。好吧,讓我們開始單元測試之旅。
下載TestDriven:http://www.testdriven.net/default.aspx
下載NUnit:http://www.nunit.org/index.php?p=download
NUnit名氣非常大,而且功能也很強,儘管NUnit支持GUI和Console兩種工作方式,但是它使用起來確實不夠直觀,我們不得不不停地切換窗口以看到測試結果。而TestDriven就非常方便,它和Visual Studio .Net2003和2005都集成的非常好,做到了即指即測。能較大的提高我們測試的效率。在安裝好TestDriven後,就可以看到下面的一個小小的圖標。
我們可以針對整個測試文件和單個函數進行測試,非常方便。下面主要談談TestDriven支持的屬性和參數。
2 TestDriven支持的一些重要的屬性
TestDriven其實可以支持大部分NUnit支持的屬性,但是有些屬性是無法支持的。其實對於自己進行單元測試來說,只需要知道常用的10多個屬性就可以進行很好的測試了。下面就最常用和最重要的屬性做一些解釋。
在開始測試之前,記得引用nunit.framework這個dll,然後
2.1 [TestFixture] 屬性
這個屬性通常是用來修飾測試類,表明這個類是用於測試的。一般把它放在類聲明的上面,就像下面這樣
//這個類是一個用來執行單元測試的類
public class TestSimpleCalculator
{
// something
}
2.2 [TestFixtureSetUp] 屬性
這個屬性通常用來修飾一個方法,表明這個方法先於所有測試方法之前運行,類似於構造函數。那麼我們可以用來初始化一些對象等,非常有用。
public class UnitTestDemo
{
SimpleCalculator myMath;
//在所有測試方法運行之前運行
[TestFixtureSetUp]
public void InitFixture()
{
myMath = new SimpleCalculator();
}
}
2.3 [TestFixtureTearDown] 屬性
這個屬性也是用於修飾方法,它會在所有測試方法運行完畢以後運行。你可以用它來釋放一些資源。
public class UnitTestDemo
{
SimpleCalculator myMath;
//在所有測試方法運行完之後運行
[TestFixtureTearDown]
public void InitFixture()
{
//釋放一些資源
myMath.Dispose();
}
}
2.4 [SetUp]屬性
這個屬性用來修飾方法,表明它會在每一個測試方法運行之前運行。那麼可以用它來重設一些變量,是每個方法在運行之前都有良好的初值。
public class TestSimpleCalculator
{
SimpleCalculator myMath;
private double a;
private double b;
// 在任何一個測試方法運行之前運行,可以用來重置一些變量
[SetUp]
public void Init()
{
a = 3.0;
b = 5.0;
}
}
2.5 [TearDown]屬性
這個屬性通常用來修飾方法,表明這個方法會在每個測試方法運行完之後運行一次。 可以用來清理一些變量或者環境。
public class TestSimpleCalculator
{
SimpleCalculator myMath;
StringBuilder sb;
[TestFixtureSetUp]
public void InitFixture()
{
myMath = new SimpleCalculator();
sb = new StringBuilder();
}
// 在每一個測試方法運行完了之後都會運行,可以用來清理一些暫存變量
[TearDown]
public void Teardown()
{
sb.Remove( 0, sb.Length );
}
}
2.6 [Test]屬性
這個屬性是最有用處的,因爲它表明這是一個測試方法。
public class TestSimpleCalculator
{
SimpleCalculator myMath;
private double a; // a = 3.0
private double b; // b = 5.0
// 這是一個測試方法
[Test]
public void Add()
{
Assert.AreEqual( a, 3.0 ); // 返回真
Assert.AreEqual( b, 5.0 );// 返回真
a = myMath.Add( a, b );
Assert.AreEqual(a, 7.0, "The expect result is 7, and the actual result is 8");// 返回假,並且會打印出錯誤信息
}
}
2.7 [ExpectedException(typeof(OneSupportedException))] 屬性
這個屬性其實非常有用處,它表明這個函數會拋出一個預期的異常。在一個項目中,異常的處理是不可避免的。如果異常處理機制不好的話,會給程序帶來相當大的混亂。也許你的程序充滿了try,catch,但是確總也捕捉不到自己想要的異常。混亂的異常對於程序員來說就是災難。
[ExpectedException(typeof(InvalidOperationException))]
public void ExpectAnException()
{
throw new InvalidCastException();// 這個地方拋出了非預期的異常,所以測試方法失敗。
}
2.8 [Ignore("name")]屬性
這個屬性也挺有用處,它表示這個測試方法會被忽略掉。也許你的代碼進行了一些升級,以前的測試方法已經不再重要,但是你仍然希望保留它們。那麼你儘可以把它們標誌成Ignore,然後統一放到一個文件或者Region中,以做存檔之用。
[Ignore("ignored test")]
[ExpectedException(typeof(InvalidOperationException))]
public void IgnoredTest()
{
throw new Exception(); // 如果可以運行這個測試方法,那麼這個方法不會通過測試,但是現在它已經被忽略掉了。
}
2.9 [Platform("SupportedPlatform")]屬性
這個屬性也相當實用,它表明這個測試方法會運行在指定的平臺上。大家都知道,.Net Framework就有幾個版本,還有各種版本的Windows系統。不同的版本對於某些類庫或者API的支持是不一樣的。比如WMI查詢語句的某些用法在Win2000上就無法通過測試。某些類庫在.net1.1中無法找到,如果指定了平臺,就一切都變得井井有條了。
[Platform("NET-1.1")]
//更多支持的平臺請查閱NUnit的文檔
public void DotNetOneOneTests()
{
Assert.AreEqual( "This case run on .Net1.1", "This method will not be executed" ); // 這個測試方法只會運行在.Net1.1的平臺下。
}
2.10 [Category("NameOfCategory")]屬性
這個屬性也很好。但是在TestDriven中無法使用。它表明我們可以把某些測試歸成一類(Category),我們可以給這個類別取個名字,然後可以指定是否對這個類別進行測試。假設你有個函數需要運行很長的時間,你肯定不希望每次都去運行它。那麼你可以把它歸到某個類別中,然後在NUnit的GUI中將它排除在測試範圍之外。
[Category("Long")]
// 這個測試方法屬於名字爲Long的類別,我們可以在NUnit的GUI中選擇是否需要運行這一類別的測試方法,但是TestDriven.net無法使用這個屬性。
public void VeryLongTest()
{
Assert.AreEqual( "This test will consum a very long time", "No, It will be completed in 0.1 seconds");
}
2.11 [Explicit]屬性
這個屬性和Ignore有相似之處,但是也有不同。如果指定了這個屬性,那麼在測試的時候是不會運行的。但是如果你指定了它(比如你把鼠標放在這個方法上,然後選擇RunTest)這個測試方法就會運行。它也非常有用處,對於某些你想暫時避過的測試,它是一個好的選擇。
public void ExplicitTest()
{
Assert.AreEqual(1, 2); // 這個測試方法會自動地被忽略掉,除非我們在NUnit的GUI中手動選擇它或者把鼠標放在它上面,再運行TestDriven.net, 它纔會被執行
}
3 總結
其實NUnit的實際功能比我上面列舉的強大得多。但是對於程序員自己單元測試來說,瞭解一些常用的屬性就已經足夠。TestDriven支持大部分屬性,使用起來也非常的方便。而且TestDriven還能提供NCover這個分析的利器。你大可以爲自己的應用程序創建一個工程,同時還爲自己的測試代碼創建一個工程,測試和開發同步進行。良好的單元測試一定可以提高程序的質量,同時也未必會耽誤太多時間,延緩項目的進度。單元測試是如此的簡單,也是如此的有用。希望上面的這些屬性對大家有所幫助,能夠提高大家的程序水平。