[小北De編程手記] : Lesson 03 玩轉 xUnit.Net 之 Fixture(上) [小北De編程手記] : Selenium For C# 教程 [小北De編程手記] : Seleni

  在使用xUnit.Net Framework構建單元測試或自動化測試項目的時候,不管是針對一些比較耗費資源的對象亦或是爲了支持Test case預設數據的能力,咱們都須要有一些初始化或是清理相關的動做。在xUnit.Net中,提供了多種方式來知足咱們的須要。仍是照例看一下本文要討論的內容:html

  • xUnit.Net 共享數據的方式(上)
  • Test Case的構造函數 & IDisposable.Dispose(上)
  • Class級別的Fixture : IClassFixture(上)
  • Collection級別的Fixture : ICollectionFixture(下)
  • 依賴注入以及輸出日誌(下)

  本文咱們只是討論前三個議題,其餘的議題我會在《xUnit.Net 之 Fixture(下)》中討論。git

  首先,咱們虛擬一個自動化測試中很容易遇到的一個場景。有四個Test case以下圖所示:github

  

  能夠看到,其中前三個Case(測試功能01,02,03)步驟以下,建立DB鏈接->打開瀏覽器->執行功能->關閉瀏覽器->釋放數據庫鏈接。而功能測試04僅僅是須要操做數據庫而已,沒有操做瀏覽器的需求。所以,不須要在瀏覽器中進行操做。對於這樣的一個場景,直接能想到的方法是編寫4個測試方法打上前面的[Fact]標籤,每一個方法中建立數據庫鏈接,打開瀏覽器,操做,而後釋放數據庫,關閉瀏覽器。但這樣的作法有不少的問題,好比會屢次佔用瀏覽器驅動和數據庫鏈接這樣的非託管資源。而打開數據庫鏈接和瀏覽器驅動每每是比較耗時的操做,屢次打開會無故的增長Test case的運行時間。數據庫

  那麼,如何來設計測試步驟呢?這裏,我建議知足下面幾個條件(固然也是爲了講解今天的內容):編程

  • 在每一個測試任務開始以前作一些數據的初始化工做。
  • 打開一次瀏覽器,完成測試功能01,02,03以後,在關閉瀏覽器。在減小建立瀏覽器的開銷的同時節省了測試時間
  • 在應用程序級別統一建立數據庫鏈接,Test Case 使用的數據庫鏈接是同一份(或是統一管理的)。

(一)xUnit.Net 共享數據的方式

  對於以前描述的業務場景,咱們須要在每一個Test Case執行先後,一組Test Case執行先後,全部Test Case執行先後這三個維度上添加自定義的操做。對應下來:瀏覽器

  • 每一個Test Case執行先後 : 在每一個測試任務開始以前作一些數據的初始化工做。
  • 一組Test Case執行先後 : 打開一次瀏覽器,完成測試功能01,02,03以後,再關閉瀏覽器。
  • 全部Test Case執行先後 : 在應用程序級別統一建立數據庫鏈接。

  如圖所示,CollectionFixture能夠用於添加全部Test Case執行先後的一些操做(即例子中的建立和銷燬數據庫鏈接)。對於部分Case須要初始化瀏覽器,咱們可使用ClassFixture提供的功能。每一個Case執行先後的操做咱們可使用測試類構造函數和IDisposable.Dispose來進行處理。下面我就逐一爲你們講解如何使用這些功能。框架

(二)Test Case的構造函數 & IDisposable.Dispose

  如何在每一個Test Case執行先後作處理?這應該是每一個使用過單元測試框架的同窗都知道的。多數的框架都是經過打標籤的方式來提供相似功能的,例如:NUnit的[Setup]和[TearDown] , MSTest的[TestInitialize]和[TestCleanup]。而xUnit.Net提供了一種更加優雅的處理方式,就是利用構造函數以及IDisposable.Dispose方法來實現對應的功能。懂得一些面向對象的小夥伴也許會發現,這樣的改進主要是爲了支持依賴注入(而不是簡單的省去了標籤而已)。這也爲我後續的文章中要講到的許多功能的注入實現提供了可能。講了這麼多理論,先上一段Code:函數

 1 namespace Demo.UnitTest.Lesson03_Fixture
 2 {
 3     public class SharedContext_Constructor : IDisposable
 4     {
 5         private ITestOutputHelper _output;
 6         public SharedContext_Constructor(ITestOutputHelper output)
 7         {
 8             this._output = output;
 9             _output.WriteLine("Execute constructor!");
10         }
11 
12         #region Test case
13         [Fact(DisplayName = "SharedContext.Constructor.Case01")]
14         public void TestCase01()
15         {
16             _output.WriteLine("Execute case 01!");
17         }
18 
19         [Fact(DisplayName = "SharedContext.Constructor.Case02")]
20         public void TestCase02()
21         {
22             _output.WriteLine("Execute case 02!");
23         }
24 
25         [Fact(DisplayName = "SharedContext.Constructor.Case03")]
26         public void TestCase03()
27         {
28             _output.WriteLine("Execute case 03!");
29         }
30         #endregion
31 
32         public void Dispose()
33         {
34             _output.WriteLine("Execute dispose!");
35         }
36     }
37 }

  代碼中的ITestOutputHelper就是經過構造函數注入的方式爲咱們提供了輸出Log的能力(這個下一篇的文章我會爲你們講解),這裏你只須要知道他是能夠輸出一些日誌的便可。上面的Code中,有3個Case,Case執行的時Runner會在執行每一個Case先後分別調用測試類的構造函數和對應的Dispose方法。輸出以下,咱們能夠看到測試類構造函數和Dispose方法在每個Case執行先後都被執行。post

(三)Class級別的Fixture : IClassFixture

  ok,如今咱們考慮前文中提到的問題二:僅僅打開一次瀏覽器,完成測試功能01,02,03以後,再關閉瀏覽器。xUnit.Net爲咱們提供了基於類級別的Fixture,即IClassFixture。IClassFixture是一個泛型接口(標記接口,沒有任何須要實現的方法),接受一個類型。該類型的構造函數會在測試類中的第一個Test Case運行以前被調用。而其IDisposable.Dispose方法會在測試類中最後一個測試方法執行完成以後被執行。IClassFixture定義以下:單元測試

1 namespace Xunit
2 {
3     public interface IClassFixture<TFixture> where TFixture : class
4     {
5     }
6 }

  如何使用IClassFixture呢?步驟以下:

  Step 01 : 建立自定義的Fixture類,添加構造函數和IDisposable接口的實現方法。本文主要是講解xUnit.Net的使用,所以示例代碼中我沒有給出建立瀏覽器驅動的具體代碼(這部份內容能夠參見個人另外一個系列《[小北De編程手記] : Selenium For C# 教程》),只是添加了ExecuteCount屬性用於標記執行次數,代碼以下:

 1     public class SingleBrowserFixture : IDisposable
 2     {
 3         public int UserId { get; set; }
 4         public string UserName { get; set; }
 5         public static int ExecuteCount;
 6 
 7         public SingleBrowserFixture()
 8         {
 9             this.UserId = 1;
10             this.UserName = "North";
11             ExecuteCount++;
12 
13             //打開瀏覽器...
14         }
15 
16         public void Dispose()
17         {
18             //關閉瀏覽器...
19         }
20     }

  Step 02 :建立具體的測試類,並繼承 IClassFixture<SingleBrowserFixture>(注意:咱們用接口標記須要使用哪個類)

  Step 03 :在測試類中獲取Fixture對象,xUnit.Net 用構造函數注入的方式提供了獲取IClassFixture標記對象的方法。咱們能夠在測試類的構造函數中添加對應的注入參數來獲取Fixture,這樣的設計使得咱們在測試類中全部的測試用例中共享一些Context數據,xUnit.Net執行測試用例的時候會自動識別構造參數的類型是否和IClassFixture所標記的類型是否匹配。代碼以下:

 1     public class SharedContext_ClassFixture : IClassFixture<SingleBrowserFixture>
 2     {
 3         ITestOutputHelper _output;
 4         SingleBrowserFixture _fixture;
 5         static int _count;
 6         public SharedContext_ClassFixture(ITestOutputHelper output, SingleBrowserFixture fixture)
 7         {
 8             _output = output;
 9             _fixture = fixture;
10             _count++;
11         }
12         #region Test case
13         [Fact(DisplayName = "SharedContext.ClassFixture.Case01")]
14         public void TestCase01()
15         {
16             _output.WriteLine("Execute case 01! Current User:[{0}]-{1}", _fixture.UserId, _fixture.UserName);
17             _output.WriteLine("Execute count! Constructor:[{0}] , ClassFixture:[{1}]", _count, SingleBrowserFixture.ExecuteCount);
18 
19         }
20 
21         [Fact(DisplayName = "SharedContext.ClassFixture.Case02")]
22         public void TestCase02()
23         {
24             _output.WriteLine("Execute case 01! Current User:[{0}]-{1}", _fixture.UserId, _fixture.UserName);
25             _output.WriteLine("Execute count! Constructor:[{0}] , ClassFixture:[{1}]", _count, SingleBrowserFixture.ExecuteCount);
26         }
27         #endregion Test case
28     }

  代碼中能夠看到,我用_count 標記了測試類的執行次數,用ExecuteCount標記Fixture類的執行次數,看下運行結果:

  能夠看到,測試類的構造被執行了2次(也就是每一個測試用例執行的時候都會執行一次),而ClassFixture標記的測試類中的構造函數只是被執行了一次。IDisposable.Dispose 也具備相同的邏輯。

  下一篇,爲你們介紹:

  • Collection級別的Fixture : ICollectionFixture(下)
  • 依賴注入以及輸出日誌(下)

小北De系列文章:

  《[小北De編程手記] : Selenium For C# 教程

  《[小北De編程手記]:C# 進化史》(未完成)

  《[小北De編程手記]:玩轉 xUnit.Net》(未完成)

Demo地址:https://github.com/DemoCnblogs/xUnit.Net

若是您認爲這篇文章還不錯或者有所收穫,能夠點擊右下角的 【推薦】按鈕,由於你的支持是我繼續寫做,分享的最大動力!
做者:小北@North
來源:http://www.cnblogs.com/NorthAlan
聲明:本博客原創文字只表明本人工做中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未受權,貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
相關文章
相關標籤/搜索