xUnit.net:グローバルセットアップ+ティアダウン?


98

この質問は、ユニットテストフレームワークxUnit.netに関するものです。

テストを実行する前にコードを実行する必要があります。また、すべてのテストを実行した後にコードを実行する必要があります。グローバルな初期化および終了コードを示すために、ある種の属性またはマーカーインターフェイスがあるべきだと思いましたが、それらを見つけることができませんでした。

または、xUnitをプログラムで呼び出すと、次のコードで必要な処理を実行できます。

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

誰かがいくつかのグローバルなセットアップ/ティアダウンコードを宣言的またはプログラム的に実行する方法についてのヒントを教えてもらえますか?


1
私はここで推測する答えである:stackoverflow.com/questions/12379949/...
the_joric

回答:


118

私の知る限り、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>インターフェイスを使用して、グローバル初期化/破棄機能が1回だけ呼び出されるようにします。このバージョンでは、テストクラスから基本クラスを拡張せず、フィクスチャクラスを参照する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 DummyTests(TestsFixture data)
    {
    }
}

これはされますが、コンストラクタにつながるTestsFixtureだけでテスト中のクラスごとに一度実行されています。したがって、2つの方法のどちらを選択するかによって異なります。


4
IUseFixtureはもはや存在せず、IClassFixtureに置き換えられたようです。
GaTechThomas 2015

9
これは機能しますが、Geir Sagbergからの回答のCollectionFixtureは、この目的のために特別に設計されたため、このシナリオに適しています。また、テストクラスを継承する必要はありません。[Collection("<name>")]属性でマークするだけです
MichelZ

8
非同期セットアップとティアダウンを行う方法はありますか?
Andrii

MSもIClassFixtureソリューションを実装しているようです。docs.microsoft.com/en-us/aspnet/core/test/...
lbrahim

3
XUnitには、テストメソッドごと、テストクラスごと、および複数のテストクラスにわたる3つの初期化オプションがあります。ドキュメントはこちら:xunit.net/docs/shared-context
GHN

48

私は同じ答えを探していましたが、現時点では、クラスフィクスチャとコレクションフィクスチャを実装する方法に関して、xUnitのドキュメントが非常に役立ちます。これにより、開発者はクラスまたはクラスのグループレベルで幅広いセットアップ/ティアダウン機能を利用できます。これはGeir Sagbergからの回答と一致しており、それがどのように見えるかを説明するための優れたスケルトン実装を提供します。

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

コレクションフィクスチャ使用するタイミング:単一のテストコンテキストを作成し、それを複数のテストクラスのテスト間で共有し、テストクラスのすべてのテストが終了した後にクリーンアップする場合。

複数のテストクラス間でフィクスチャオブジェクトを共有したい場合があります。クラスフィクスチャに使用されるデータベースの例は素晴らしい例です。データベースを一連のテストデータで初期化し、そのテストデータをそのままにして、複数のテストクラスで使用できます。xUnit.netのコレクションフィクスチャ機能を使用して、複数のテストクラスのテスト間で単一のオブジェクトインスタンスを共有できます。

コレクションフィクスチャを使用するには、次の手順を実行する必要があります。

フィクスチャクラスを作成し、スタートアップコードをフィクスチャクラスコンストラクターに配置します。フィクスチャクラスがクリーンアップを実行する必要がある場合は、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がテストを並行して実行する場合の実行方法にも影響します。詳細については、「テストの並列実行」を参照してください。

重要な注意:フィクスチャーは、それを使用するテストと同じアセンブリにある必要があります。


1
「テストコレクションはIClassFixture <>で装飾することもできます。xUnit.netは、これを、テストコレクション内の個々のテストクラスがクラスフィクスチャで装飾されているかのように扱います。」私はその例を得ることができますか?よくわかりません。
rtf '19

@TannerFaulknerクラスフィクスチャは、従来の.netユニットテストプロジェクトでTest Initializeメソッドを使用する場合と同様に、クラスレベルのセットアップとティアダウンを行う方法でした。[TestInitialize] public void Initialize(){
Larry Smith

これに関して私が持っている唯一の問題Collectionは、「グローバルな」セットアップを行うために、テストクラスを属性で装飾する必要があることです。つまり、-any-テストを実行する前に設定したいものがあれば、この属性で-all-テストクラスを装飾する必要があります。単一のテストクラスを装飾することを忘れると、追跡が困難なエラーが発生する可能性があるため、これは私の意見ではあまりにも脆弱です。xUnitが真にグローバルなセットアップとティアダウンの方法を作成できれば、すばらしいことです。
ゾッドマン

13

簡単で簡単な解決策があります。Fody.ModuleInitプラグインを使用する

https://github.com/Fody/ModuleInit

これはnugetパッケージであり、インストールするとModuleInitializer.cs、プロジェクトに呼び出される新しいファイルが追加されます。ここには、ビルド後にアセンブリに組み込まれる静的メソッドが1つあります。これは、アセンブリが読み込まれた直後に、何かが実行される前に実行されます。

これを使用して、購入したライブラリのソフトウェアライセンスのロックを解除します。各テストでライセンスのロックを解除するのを忘れていましたし、ロックを解除する基本クラスからテストを派生することさえ忘れていました。このライブラリを書いた明るい火花は、ライセンスがロックされていると告げる代わりに、テストが失敗したり、そうでないときにパスしたりする微妙な数値エラーを導入しました。ライブラリを正しくロック解除したかどうかは決してわかりません。だから今私のモジュールのinitは次のようになります

/// <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単体テストではまだ機能しないようです。
Jeff Dunlop

12

複数のクラス間でSetUp / TearDownコードを共有するには、xUnitのCollectionFixtureを使用できます。

見積もり:

コレクションフィクスチャを使用するには、次の手順を実行する必要があります。

  • フィクスチャクラスを作成し、スタートアップコードをフィクスチャクラスコンストラクターに配置します。
  • フィクスチャクラスがクリーンアップを実行する必要がある場合は、フィクスチャクラスにIDisposableを実装し、クリーンアップコードをDispose()メソッドに配置します。
  • コレクション定義クラスを作成し、[CollectionDefinition]属性で装飾して、テストコレクションを識別する一意の名前を付けます。
  • ICollectionFixture <>をコレクション定義クラスに追加します。
  • テストコレクション定義クラスの[CollectionDefinition]属性に指定した一意の名前を使用して、コレクションの一部となるすべてのテストクラスに[Collection]属性を追加します。
  • テストクラスがフィクスチャインスタンスにアクセスする必要がある場合は、それをコンストラクタ引数として追加すると、自動的に提供されます。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.