ASP.NET Core+NUnitでインテグレーションテスト

# はじめに
ASP.NET CoreではコントローラーやRazorPagesに対するインテグレーションテストを想定して、インメモリでテスト用Webサーバーをホストするための`WebApplicationFactory`クラスがあらかじめ用意されています。このクラスの利用方法は[ASP.NET Core MVC アプリのテスト](https://docs.microsoft.com/ja-jp/dotnet/architecture/modern-web-apps-azure/test-asp-net-core-mvc-apps)にまとめられていますが、対象がXUnitになっているためNUnitの場合このままでは利用できません。
この記事では、ASP.NET Core+NUnitを利用したインテグレーションテストの開始方法を説明します。

# テスト用プロジェクトの作成と必要なパッケージのインストール

dotnetコマンドで作られるテスト対象のWebApiプロジェクトと、NUnitを利用したテストプロジェクトを追加していきます。
テストプロジェクトはテスト対象のWebApiプロジェクトに対する参照と、`WebApplicationFactory`クラスを利用するために`Microsoft.AspNetCore.Mvc.Testing`パッケージを追加します。

``` sh
dotnet new webapi -o ASPNETCoreNUnitItSample/WebApi
dotnet new nunit -o ASPNETCoreNUnitItSample/WebApi.Tests

cd ASPNETCoreNUnitItSample
dotnet new sln
dotnet sln add ./WebApi/WebApi.csproj
dotnet sln add ./WebApi.Tests/WebApi.Tests.csproj

dotnet add ./WebApi.Tests/WebApi.Tests.csproj reference --interactive ./WebApi/WebApi.csproj
dotnet add ./WebApi.Tests/WebApi.Tests.csproj package Microsoft.AspNetCore.Mvc.Testing
```

Visual Studioでソリューションを開くと、次のような構成のソリューションが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/040c0f0d-16ae-2d7d-2c84-b4221824160a.png)

# インテグレーション用テスト用Webサーバーの起動コードを追加

まずはプロジェクトファイルの`<Project Sdk="Microsoft.NET.Sdk">`を`<Project Sdk="Microsoft.NET.Sdk.Web">`に変更します。

``` xml:WebApiTests.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.1" />
    <PackageReference Include="NUnit" Version="3.12.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\WebApi\WebApi.csproj" />
  </ItemGroup>

</Project>
```

続いて、テスト用Webサーバーの起動クラスを追加します。

``` cs:ApiWebApplicationFactory.cs
using Microsoft.AspNetCore.Mvc.Testing;

namespace WebApi.Tests
{
    public class ApiWebApplicationFactory: WebApplicationFactory<WebApi.Startup>
    {
    }
}
```

# テストコードの追加

XUnitの例では、`IClassFixture<T>`を継承することで`WebApplicationFactory`のインスタンスを取得していましたが、NUnitでは`IClassFixture`は使えないので、OneTimeSetup属性で指定したメソッドで`ApiWebApplicationFactory`を作成し、HttpClientを取り出してこれを利用します。

``` cs:WeatherForecastControllerTest.cs
using System.Net.Http;
using System.Threading.Tasks;
using NuGet.Frameworks;
using NUnit.Framework;

namespace WebApi.Tests.Controllers
{
    [TestFixture]
    class WeatherForecastControllerTest
    {
        private HttpClient _httpClient;

        [OneTimeSetUp]
        public void OneTimeSetup()
        {
            var factory = new ApiWebApplicationFactory();
            _httpClient = factory.CreateClient();
        }

        [Test]
        public async Task GetTest()
        {
            var response = await _httpClient.GetAsync("/WeatherForecast");
            Assert.IsTrue(response.IsSuccessStatusCode);
        }
    }
}
```

# まとめ

- NUnitでインテグレーションテストを実施する場合は、自分で`Microsoft.AspNetCore.Mvc.Testing`パッケージを追加する
- Factoryの生成はOneTimeSetupで指定したメソッドで実施する

実際にインテグレーションテストを実施する場合は、ConfigureWebHostメソッドをオーバーライドしてデータベースの参照先をRDBからメモリーデータベースにしたり、外部サービスをモックに差し替えるなどいくつか追加で実施する必要がありますが、実施方法はXUnitと変わりがありませんので[ASP.NET Core MVC アプリのテストのASP.NET Core アプリを機能テストする](https://docs.microsoft.com/ja-jp/dotnet/architecture/modern-web-apps-azure/test-asp-net-core-mvc-apps#functional-testing-aspnet-core-apps)を参照してください。