web-dev-qa-db-ja.com

ユニットテストをシリアルに(並列ではなく)実行する

私が書いたWCFホスト管理エンジンの単体テストを試みています。エンジンは基本的に、構成に基づいてその場でServiceHostインスタンスを作成します。これにより、新しいサービスが追加されたり古いサービスが削除されるたびに、すべてのサービスを停止して再起動することなく、利用可能なサービスを動的に再構成できます。

ただし、ServiceHostの動作方法が原因で、このホスト管理エンジンの単体テストが困難になりました。特定のエンドポイントに対してServiceHostが既に作成、開かれ、まだ閉じられていない場合、同じエンドポイントの別のServiceHostを作成できず、例外が発生します。最新の単体テストプラットフォームではテストの実行が並列化されるため、このコードを単体テストする効果的な方法はありません。

私はxUnit.NETを使用しましたが、その拡張性のために、強制的にテストをシリアルに実行する方法を見つけることができると期待しています。しかし、私は運がありませんでした。ここで誰かがSOで同様の問題に遭遇し、単体テストをシリアルに実行する方法を知っていることを望んでいます。

注: ServiceHost は、Microsoftによって作成されたWCFクラスです。私はそれの振る舞いを変える能力を持っていません。各サービスエンドポイントを1回だけホストすることも適切な動作です。ただし、単体テストには特に役立ちません。

69
jrista

上記のように、すべての適切な単体テストは100%分離する必要があります。共有状態(たとえば、各テストで変更されるstaticプロパティに依存する)を使用することは、悪い習慣と見なされます。

そうは言っても、xUnitテストを順番に実行することについての質問には答えがあります!私のシステムは静的なサービスロケーターを使用しているため、まったく同じ問題が発生しました(これは理想的ではありません)。

デフォルトでは、xUnit 2.xはすべてのテストを並行して実行します。これは、テストプロジェクトのAssemblyInfo.csでCollectionBehaviorを定義することにより、アセンブリごとに変更できます。

アセンブリごとの分離の場合:

using Xunit;
[Assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]

または、まったく並列化しない場合:

[Assembly: CollectionBehavior(DisableTestParallelization = true)]

後者はおそらくあなたが望むものです。並列化と構成の詳細については、 xUnit documentation をご覧ください。

78
Squiggle

各テストクラスは一意のテストコレクションであり、その下のテストは順番に実行されるため、すべてのテストを同じコレクションに入れると、順番に実行されます。

XUnitでは、これを達成するために次の変更を行うことができます。

以下が並行して実行されます:

namespace IntegrationTests
{
    public class Class1
    {
        [Fact]
        public void Test1()
        {
            Console.WriteLine("Test1 called");
        }

        [Fact]
        public void Test2()
        {
            Console.WriteLine("Test2 called");
        }
    }

    public class Class2
    {
        [Fact]
        public void Test3()
        {
            Console.WriteLine("Test3 called");
        }

        [Fact]
        public void Test4()
        {
            Console.WriteLine("Test4 called");
        }
    }
}

それをシーケンシャルにするには、両方のテストクラスを同じコレクションに入れるだけです:

namespace IntegrationTests
{
    [Collection("Sequential")]
    public class Class1
    {
        [Fact]
        public void Test1()
        {
            Console.WriteLine("Test1 called");
        }

        [Fact]
        public void Test2()
        {
            Console.WriteLine("Test2 called");
        }
    }

    [Collection("Sequential")]
    public class Class2
    {
        [Fact]
        public void Test3()
        {
            Console.WriteLine("Test3 called");
        }

        [Fact]
        public void Test4()
        {
            Console.WriteLine("Test4 called");
        }
    }
}

詳細については、 このリンク を参照してください。

62
Abhinav Saxena

.NET Coreプロジェクトの場合、xunit.runner.json with:

{
  "parallelizeAssembly": false,
  "parallelizeTestCollections": false
}

また、csprojには

<ItemGroup>
  <None Update="xunit.runner.json"> 
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

古い.Net Coreプロジェクトの場合、project.jsonを含む必要があります

"buildOptions": {
  "copyToOutput": {
    "include": [ "xunit.runner.json" ]
  }
}
48

.NET Coreプロジェクトの場合、 https://xunit.github.io/docs/configuring-with-json.html で文書化されているように、xunit.runner.jsonファイルでxUnitを構成できます。

並列テストの実行を停止するために変更する必要がある設定はparallelizeTestCollectionsで、デフォルトはtrueです。

アセンブリがこのアセンブリ内で互いに並行してテストを実行する場合、これをtrueに設定します。 ...これをfalseに設定して、このテストアセンブリ内のすべての並列化を無効にします。

JSONスキーマタイプ:boolean
デフォルト値:true

そのため、この目的のための最小限のxunit.runner.jsonは次のようになります

{
    "parallelizeTestCollections": false
}

ドキュメントに記載されているように、次のいずれかの方法で、このファイルをビルドに含めることを忘れないでください。

  • 設定出力ディレクトリにコピー新しい場合にコピーファイルのプロパティに、または
  • 追加中

    <Content Include=".\xunit.runner.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    

    .csprojファイル、または

  • 追加中

    "buildOptions": {
      "copyToOutput": {
        "include": [ "xunit.runner.json" ]
      }
    }
    

    project.jsonファイルに

プロジェクトのタイプに応じて。

最後に、上記に加えてさらに、Visual Studioを使用している場合は、誤ってテストを並行して実行ボタンをクリックしていないことを確認してください。 xunit.runner.jsonで並列化をオフにしている場合でも、並列に実行します。 MicrosoftのUIデザイナーは、誤ってボタンを押す可能性を最大化するために、このボタンをラベルなし、気づきにくく、テストエクスプローラーの"Run All"ボタンから約1センチ離しています。また、テストが突然失敗する理由がわかりません。

Screenshot with the button circled

15
Mark Amery

Playlistを使用できます

テストメソッドを右クリック->プレイリストに追加->新しいプレイリスト

実行順序を指定できます。デフォルトでは、プレイリストに追加しますが、プレイリストファイルは必要に応じて変更できます

enter image description here

6
HB MAAM

詳細はわかりませんが、単体テストではなく統合テストをしようとしているようです。 ServiceHostへの依存関係を分離できれば、テストが簡単(かつ高速)になります。 (たとえば)次を個別にテストできます。

  • 構成読み取りクラス
  • ServiceHostファクトリー(おそらく統合テストとして)
  • IServiceHostFactoryIConfigurationをとるエンジンクラス

分離(モック)フレームワークおよび(オプションで)IoCコンテナーフレームワークを含めるのに役立つツール。見る:

5
TrueWill

Advanced Unit Testing を使用できます。 テストを実行する順序を定義できます 。そのため、これらのテストをホストするために新しいcsファイルを作成する必要があります。

テスト方法を曲げて、希望する順序で機能させる方法を次に示します。

[Test]
[Sequence(16)]
[Requires("POConstructor")]
[Requires("WorkOrderConstructor")]
public void ClosePO()
{
  po.Close();

  // one charge slip should be added to both work orders

  Assertion.Assert(wo1.ChargeSlipCount==1,
    "First work order: ChargeSlipCount not 1.");
  Assertion.Assert(wo2.ChargeSlipCount==1,
    "Second work order: ChargeSlipCount not 1.");
  ...
}

動作するかどうか教えてください。

3
Graviton