🚙

[xUnit.net] 全体で1回だけ行う初期化処理を定義する

2021/04/16に公開

テストを作る際、アセンブリ全体で一番最初に一回だけ走る初期化処理を書きたいことがあります。その方法をまとめておきます。

本記事で対象とするのは.NET Core 3.1 または .NET 5です。テストのフレームワークはxUnit.netとします。

.NET Core以降では、個人的に以下が必要になるシーンが時々あります[1]。例にとって進めます。

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=net-5.0

以下は実行したいテストの例です[2]Encoding.RegisterProviderの準備無しに実行すると失敗します。

MyTest.cs
using Microsoft.VisualBasic;
using Xunit;

public class MyTest
{
    [Fact]
    public void Test()
    {
        var result = Strings.StrConv("1", VbStrConv.Narrow);
	Assert.Equal("1", result);
    }
}

1. IClassFixture

https://xunit.net/docs/shared-context

xUnit.netの流儀に則った方法です。テストクラスが増えるたびにIClassFixtureを付ける(実装する)のが面倒または忘れがちという欠点はあります。

EncodingFixture.cs
public class EncodingFixture
{
    public EncodingFixture()
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    }
}
MyTest.cs
public class MyTest : IClassFixture<EncodingFixture>
{
    [Fact]
    public void Test()
    {
        var result = Strings.StrConv("1", VbStrConv.Narrow);
	Assert.Equal("1", result);
    }
}

2. Xunit.DependencyInjection

以下のNuGetを参照します。
https://www.nuget.org/packages/Xunit.DependencyInjection
https://github.com/pengweiqhca/Xunit.DependencyInjection

詳細はGitHubのREADME等をご覧いただきたいですが、いつものGeneric Hostの流儀通りStartupクラスを作っておけば、最初に呼び出してくれます。

ロガーやシングルトンサービス等々、調整できる幅が広いです[3]。そういったものも変更したいならば、ついでにEncoding.RegisterProviderも入れさせてもらうのは良さそうです。サードパーティーのNuGetを追加することになるのがあえて言えば難点です。

Startup.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    }
}

3. [ModuleInitializer]

C# 9.0で追加された仕様です。.NET 5以降なら使えます。この方法はそもそもテストに限らず使えます。
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/module-initializers

今回の例である Encoding.RegisterProvider であれば最も楽かと思います。

Initializer.cs
internal static class Initializer
{
    [ModuleInitializer]
    public static void Initialize()
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    }
}
脚注
  1. Windowsのコマンドプロンプトに出力するとき、StrConvを使いたいとき、等です。 ↩︎

  2. Microsoft.VisualBasic は、 .NET Core以降ではNuGetで導入できます。https://www.nuget.org/packages/Microsoft.VisualBasic/ ↩︎

  3. 一例として、テストの時だけITestOutputHelperをロガーに登録する用途等があります。直接Xunit.DependencyInjectionは使っていませんが参考になる記事です: https://www.meziantou.net/how-to-get-asp-net-core-logs-in-the-output-of-xunit-tests.htm ↩︎

Discussion