利用TestDriven.net和NUnit進行單元測試

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,然後

using  NUnit.Framework;

2.1  [TestFixture] 屬性

這個屬性通常是用來修飾測試類,表明這個類是用於測試的。一般把它放在類聲明的上面,就像下面這樣

 [TestFixture]
 
//這個類是一個用來執行單元測試的類
 public class TestSimpleCalculator
 {
  
// something
 }

2.2 [TestFixtureSetUp] 屬性

這個屬性通常用來修飾一個方法,表明這個方法先於所有測試方法之前運行,類似於構造函數。那麼我們可以用來初始化一些對象等,非常有用。

[TestFixture]
 
public class UnitTestDemo
 {
  SimpleCalculator myMath;
  
  
//在所有測試方法運行之前運行
  [TestFixtureSetUp]
  
public void InitFixture()
  {
   myMath 
= new SimpleCalculator();
  }
 }

 2.3  [TestFixtureTearDown] 屬性

這個屬性也是用於修飾方法,它會在所有測試方法運行完畢以後運行。你可以用它來釋放一些資源。

 [TestFixture]
 
public class UnitTestDemo
 {
  SimpleCalculator myMath;
  
  
//在所有測試方法運行完之後運行
  [TestFixtureTearDown]
  
public void InitFixture()
  {
   
//釋放一些資源
   myMath.Dispose();
  }
 }

2.4 [SetUp]屬性

這個屬性用來修飾方法,表明它會在每一個測試方法運行之前運行。那麼可以用它來重設一些變量,是每個方法在運行之前都有良好的初值。

 [TestFixture]
 
public class TestSimpleCalculator
 {
  SimpleCalculator myMath;
  
private double a;
  
private double b;

  
// 在任何一個測試方法運行之前運行,可以用來重置一些變量
  [SetUp]
  
public void Init()
  {
   a 
= 3.0;
   b 
= 5.0;
  }
 }

2.5 [TearDown]屬性

這個屬性通常用來修飾方法,表明這個方法會在每個測試方法運行完之後運行一次。 可以用來清理一些變量或者環境。

[TestFixture]
 
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]屬性

這個屬性是最有用處的,因爲它表明這是一個測試方法。

 [TestFixture]
 
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,但是確總也捕捉不到自己想要的異常。混亂的異常對於程序員來說就是災難。

  [Test]
  [ExpectedException(
typeof(InvalidOperationException))]
  
public void ExpectAnException()
  {
   
throw new InvalidCastException();// 這個地方拋出了非預期的異常,所以測試方法失敗。
  }

2.8 [Ignore("name")]屬性

這個屬性也挺有用處,它表示這個測試方法會被忽略掉。也許你的代碼進行了一些升級,以前的測試方法已經不再重要,但是你仍然希望保留它們。那麼你儘可以把它們標誌成Ignore,然後統一放到一個文件或者Region中,以做存檔之用。

  [Test]
  [Ignore(
"ignored test")]
  [ExpectedException(
typeof(InvalidOperationException))]
  
public void IgnoredTest()
  {
   
throw new Exception(); // 如果可以運行這個測試方法,那麼這個方法不會通過測試,但是現在它已經被忽略掉了。
  }

2.9 [Platform("SupportedPlatform")]屬性

這個屬性也相當實用,它表明這個測試方法會運行在指定的平臺上。大家都知道,.Net Framework就有幾個版本,還有各種版本的Windows系統。不同的版本對於某些類庫或者API的支持是不一樣的。比如WMI查詢語句的某些用法在Win2000上就無法通過測試。某些類庫在.net1.1中無法找到,如果指定了平臺,就一切都變得井井有條了。

  [Test]
  [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中將它排除在測試範圍之外。

[Test]
  [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)這個測試方法就會運行。它也非常有用處,對於某些你想暫時避過的測試,它是一個好的選擇。

  [Test, Explicit]
  
public void ExplicitTest()
  {
   Assert.AreEqual(
12); // 這個測試方法會自動地被忽略掉,除非我們在NUnit的GUI中手動選擇它或者把鼠標放在它上面,再運行TestDriven.net, 它纔會被執行
  }

3 總結

其實NUnit的實際功能比我上面列舉的強大得多。但是對於程序員自己單元測試來說,瞭解一些常用的屬性就已經足夠。TestDriven支持大部分屬性,使用起來也非常的方便。而且TestDriven還能提供NCover這個分析的利器。你大可以爲自己的應用程序創建一個工程,同時還爲自己的測試代碼創建一個工程,測試和開發同步進行。良好的單元測試一定可以提高程序的質量,同時也未必會耽誤太多時間,延緩項目的進度。單元測試是如此的簡單,也是如此的有用。希望上面的這些屬性對大家有所幫助,能夠提高大家的程序水平。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章