2012-10-19 94 views
37

這個問題是關於單元測試框架xUnit.netxUnit.net:全局設置+拆解?

我需要在執行任何測試之前運行一些代碼,並且在完成所有測試之後還要執行一些代碼。我認爲應該有某種屬性或標記接口來指示全局初始化和終止代碼,但找不到它們。

或者,如果我調用的xUnit編程,我也可以做到什麼,我想用下面的代碼:

static void Main() 
{ 
    try 
    { 
     MyGlobalSetup(); 
     RunAllTests(); // What goes into this method? 
    } 
    finally 
    { 
     MyGlobalTeardown(); 
    } 
} 

誰能給我提供一個關於如何以聲明或編程方式運行一些全局安裝/拆卸代碼提示?

+1

我猜這裏是答案:http://stackoverflow.com/questions/12379949/xunit-resharper-how-to-run-setup-code-only-once –

回答

44

據我所知,xUnit沒有全局初始化/拆卸擴展點。但是,創建一個很容易。只需創建一個實現IDisposable的基本測試類,並在構造函數中執行初始化,並在IDisposable.Dispose方法中執行初始化。這應該是這樣的:

public abstract class TestsBase : IDisposable 
{ 
    protected TestsBase() 
    { 
     // Do "global" initialization here; Called before every test method. 
    } 

    public void Dispose() 
    { 
     // Do "global" teardown here; Called after every test method. 
    } 
} 

public class DummyTests : TestsBase 
{ 
    // Add test methods 
} 

然而,基類的安裝和拆卸的代碼將在每次調用執行。這可能不是你想要的,因爲它不是很有效。更優化的版本將使用IClassFixture<T>接口來確保僅調用一次全局初始化/拆卸功能。對於這個版本,你不會從你的測試類擴展基類,但其實現的IClassFixture<T>界面,T指的是您的夾具類:

using Xunit; 

public class TestsFixture : IDisposable 
{ 
    public TestsFixture() 
    { 
     // Do "global" initialization here; Only called once. 
    } 

    public void Dispose() 
    { 
     // Do "global" teardown here; Only called once. 
    } 
} 

public class DummyTests : IClassFixture<TestsFixture> 
{ 
    public void SetFixture(TestsFixture data) 
    { 
    } 
} 

導致TestsFixture構造函數只被運行一次 爲每個被測試的類。因此它取決於你想要在兩種方法之間進行選擇。

+3

看來IUseFixture不再存在,已被IClassFixture取代。 – GaTechThomas

+1

儘管這樣做有效,但我認爲從Geir Sagberg的答案中的CollectionFixture更適合這種情況,因爲它是專門爲此目的而設計的。你也不必繼承你的測試類,只需用'[Collection(「」)]屬性 – MichelZ

+0

標記它們有沒有什麼辦法可以做異步設置和拆卸? – Andrii

-3

應該有bootstrap選項可以在其他任何地方運行代碼。至少有PHPUnit。你沒有提到你使用的是什麼框架。

我不知道在所有測試後運行代碼的任何方式。但是你可以在一個首先運行測試的包裝腳本中執行此操作,然後運行你需要的任何東西。

+0

問題標題和標籤中都的xUnit他們。 – Codism

+1

@Codism:「xUnit」通常是指用於各種語言的單元測試套件系列。他們是一個家庭,因爲他們都是在JUnit之後建模的,而且結構非常相似。請參閱http://en.wikipedia.org/wiki/XUnit,或者將鼠標懸停在您添加到問題中的「xunit」標籤上。聽起來你正在使用.NET測試框架「xUnit」,但具體的一個是相當新的和未知的。 – DXM

+1

@DXM:謝謝澄清xunit。我會更新我的問題。 – Codism

7

有一個簡單的解決方案。使用Fody.ModuleInit插件

https://github.com/Fody/ModuleInit

這是一個NuGet包,當你安裝它,它增加了一個新的文件名爲ModuleInitializer.cs到項目中。在這裏有一個靜態方法,它在構建之後被編織到程序集中,並在程序集加載之後以及運行之前立即運行。

我使用它來解鎖我購買的庫的軟件許可證。我總是忘記在每個測試中解鎖許可證,甚至忘記從可以解鎖它的基類中派生出測試。寫這個庫的明亮的火花,而不是告訴你它是許可證鎖定引入了微妙的數字錯誤,導致測試失敗或通過時,他們不應該。你永遠不會知道你是否正確地解鎖了圖書館。所以現在我的模塊初始化看起來像

/// <summary> 
/// Used by the ModuleInit. All code inside the Initialize method is ran as soon as the assembly is loaded. 
/// </summary> 
public static class ModuleInitializer 
{ 
    /// <summary> 
    /// Initializes the module. 
    /// </summary> 
    public static void Initialize() 
    { 
      SomeLibrary.LicenceUtility.Unlock("XXXX-XXXX-XXXX-XXXX-XXXX"); 
    } 
} 

並且放入此程序集的所有測試都將正確解鎖它們的許可證。

+2

堅實的想法;不幸的是,它似乎還沒有與DNX單元測試一起工作。 –

5

要在多個類之間共享SetUp/TearDown代碼,可以使用xUnit的CollectionFixture

報價:

要使用集燈具,需要採取以下步驟:

  • 創建夾具類,並把啓動代碼的夾具類的構造函數。
  • 如果夾具類需要執行清理,請在夾具類上實現IDisposable,然後將清理代碼放入Dispose()方法 中。
  • 創建集合定義類,使用[CollectionDefinition]屬性對其進行裝飾,給它一個唯一的名稱,將 標識測試集合。
  • 將ICollectionFixture <>添加到集合定義類。
  • 使用提供給測試 集合定義類的[CollectionDefinition]屬性的唯一名稱,將[Collection]屬性添加到將成爲集合一部分的所有測試類。
  • 如果測試類需要訪問燈具實例,請將其添加爲構造函數參數,並自動提供。
15

我有點遲到了,但我一直在尋找相同的答案,而此時的xUnit文檔是非常有幫助的關於如何實現類燈具和燈具收藏,讓開發人員在班級或班級級別設置/拆卸各種功能。這與Geir Sagberg的回答一致,並提供了良好的骨架實現來說明它應該是什麼樣子。

https://xunit.github.io/docs/shared-context.html

收藏燈具 何時使用:當你想創建一個單一的測試環境和在幾個測試類測試中共享,並使其在測試類所有的測試後清理完成了。

有時你會想要在多個測試類中共享一個夾具對象。用於類裝置的數據庫示例就是一個很好的例子:您可能想用一組測試數據初始化數據庫,然後將測試數據保留在適當的位置以供多個測試類使用。您可以使用xUnit.net的集合夾具功能在多個測試類中的測試之間共享單個對象實例。

要使用集燈具,需要採取以下步驟:

創建夾具類,並把啓動代碼的夾具類的構造函數。 如果fixture類需要執行清理,請在fixture類上實現IDisposable,並將清理代碼放在Dispose()方法中。 創建集合定義類,使用[CollectionDefinition]屬性對其進行裝飾,給它一個唯一的名稱來標識測試集合。 將ICollectionFixture <>添加到集合定義類。 使用提供給測試集合定義類的[CollectionDefinition]屬性的唯一名稱,將[Collection]屬性添加到將成爲集合一部分的所有測試類。 如果測試類需要訪問燈具實例,請將其添加爲構造函數參數,並自動提供。 下面是一個簡單的例子:

public class DatabaseFixture : IDisposable 
{ 
    public DatabaseFixture() 
    { 
     Db = new SqlConnection("MyConnectionString"); 

     // ... initialize data in the test database ... 
    } 

    public void Dispose() 
    { 
     // ... clean up test data from the database ... 
    } 

    public SqlConnection Db { get; private set; } 
} 

[CollectionDefinition("Database collection")] 
public class DatabaseCollection : ICollectionFixture<DatabaseFixture> 
{ 
    // This class has no code, and is never created. Its purpose is simply 
    // to be the place to apply [CollectionDefinition] and all the 
    // ICollectionFixture<> interfaces. 
} 

[Collection("Database collection")] 
public class DatabaseTestClass1 
{ 
    DatabaseFixture fixture; 

    public DatabaseTestClass1(DatabaseFixture fixture) 
    { 
     this.fixture = fixture; 
    } 
} 

[Collection("Database collection")] 
public class DatabaseTestClass2 
{ 
    // ... 
} 

xUnit.net對待集合夾具中幾乎相同的方式爲類固定裝置,不同之處在於一個集合夾具對象的生命週期較長:它之前的任何創建測試在集合中的任何測試類中運行,並且在集合中的所有測試類完成運行之前不會清理。

測試集合也可以使用IClassFixture <>進行裝飾。 xUnit.net將此視爲好像測試集合中的每個單獨測試類都使用了類裝飾。

測試集合還會影響xUnit.net在並行運行時運行測試的方式。有關更多信息,請參閱並行運行測試。

重要提示:夾具必須與使用它們的測試在同一個裝配體中。

+0

「測試集合也可以使用IClassFixture <>進行修飾,xUnit.net將此視爲好像測試集合中的每個單獨測試類都使用了類裝飾。」任何機會我可以得到這樣的例子?我不太明白。 –

+0

@TannerFaulkner 類燈具是一種方法,有一個類級別的安裝和拆卸,就像你與傳統的.NET單元測試項目獲得,當你有一個測試初始化​​方法: [TestInitialize] 公共無效初始化(){ –

+0

Errr ....: - /我在上面的評論中應該說[ClassInitialze]。 –