コンテンツにスキップ

結合テストプロジェクトの構成⚓︎

結合テストプロジェクトの設定⚓︎

結合テスト用に xUnit のテストプロジェクトを作成し、以下を設定します。

テスト対象プロジェクトの設定⚓︎

テスト対象プロジェクトの Program.cs を部分クラス宣言を利用してテストプロジェクトに公開します。

Program.cs
1
2
3
4
var builder = WebApplication.CreateBuilder(args);
// ...
app.Run();
public partial class Program {}

internal メンバーをテストプロジェクトに公開する

テスト対象プロジェクトの internal メンバーをテストプロジェクトから参照可能にした場合にも Program.cs を公開できます。 詳細は以下を参照してください。

既定の WebApplicationFactory を使用した基本的なテスト

テストコード作成⚓︎

基本のテスト⚓︎

テストクラスに IClassFixture<TFixture> インターフェースを実装し、 WebApplicationFactory<TEntryPoint> のインスタンスをテストクラスから利用します。 WebApplicationFactory<TEntryPoint> はテスト対象アプリケーションの TestServer インスタンスを提供します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class BasicTests 
    : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> factory;

    public BasicTests(WebApplicationFactory<Program> factory)
    {
        this.factory = factory;
    }

    [Theory]
    [InlineData("/")]
    [InlineData("/Index")]
    public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
    {
        // Arrange
        // TestServerにリクエストを送信するHttpClientを取得
        var client = this.factory.CreateClient();

        // Act
        var response = await client.GetAsync(url);

        // Assert
        response.EnsureSuccessStatusCode();
        Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString());
    }
}

上記のコードでは、テスト対象のページにアクセスした際のステータスコードと Content-Type ヘッダーの内容を確認しています。

詳細は以下を参照してください。

既定の WebApplicationFactory を使用した基本的なテスト

テスト対象アプリケーションの構成設定⚓︎

システム構成が異なるローカル環境と CI 環境でテストを行う場合等、テスト対象アプリケーションの構成を変更してテストを行う際は WebApplicationFactory<TEntryPoint> クラスを継承したクラスを作成します。

以下の手順では、結合テスト用にデータベースコンテキストを差し替えています。

  1. WebApplicationFactory<TEntryPoint> クラスを継承したクラスでテスト対象アプリケーションの構成を変更する。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class CustomWebApplicationFactory<TProgram>
        : WebApplicationFactory<TProgram> where TProgram : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            var env = Environment.GetEnvironmentVariable("TEST_ENVIRONMENT") ?? Environments.Development;
    
            builder.ConfigureServices(services =>
            {
                // DbContextの設定を差し替えるためにサービス登録をいったん削除する
                services.RemoveAll<DbContextOptions<SampleDbContext>>();
    
                // テスト用の構成を読み込む
                var config = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile($"appsettings.{env}.json", optional: true, reloadOnChange: true)
                    .Build();
                var connectionString = config.GetConnectionString("SampleDbContext");
    
                // テスト用の設定を使用してDbContextをサービス登録
                services.AddDbContext<SampleDbContext>(option =>
                {
                    option.UseSqlServer(connectionString);
                });
            });
        }
    }
    
    appsettings.{env}.json の設定例

    appsettings.Development.json
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    {
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning",
                "Microsoft.AspNetCore.HttpLogging": "Information",
                "Microsoft.Extensions.Diagnostics.HealthChecks": "Debug",
                "SampleApp": "Debug"
                }
        },
        "ConnectionStrings": {
            "SampleDbContext": "Data Source=(localdb)\\mssqllocaldb;Database=SampleDb;Integrated Security=True"
        }
    }
    
    appsettings.IntegrationTest.json
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    {
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning",
                "SampleApp": "Information"
            }
        },
        "ConnectionStrings": {
            "SampleDbContext": "Server=localhost,1433;Database=SampleDb;User=<ユーザー名>;Password=<パスワード>;TrustServerCertificate=true;"
        },
        "AllowedHosts": "*"
    }
    

  2. テストクラスで実装する IClassFixture インターフェースの型引数を CustomWebApplicationFactory<Program> とする。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class IndexPageTests
        : IClassFixture<CustomWebApplicationFactory<Program>>
    {
        private readonly HttpClient client;
        private readonly CustomWebApplicationFactory<Program> factory;
    
        public IndexPageTests(CustomWebApplicationFactory<Program> factory)
        {
            this.factory = factory;
            this.client = this.factory.CreateClient();
        }
    
        [Fact]
        public async Task Get_EndpointsReturnSuccess()
        {
            // Arrange & Act
            var indexPage = await client.GetAsync("/Index");
    
            // Assert
            Assert.Equal(HttpStatusCode.OK, indexPage.StatusCode);
        }
    }
    

    上記の実装により、環境変数 TEST_ENVIRONMENT の値に応じて構成ファイルを読み込み、アプリケーションのデータベース接続先を変更しています。 ビルドマシンごとに異なる TEST_ENVIRONMENT の値を設定し、 appsettings.{TEST_ENVIRONMENT}.json を切り替えることができます。また、 IClassFixture インターフェースの型引数を CustomWebApplicationFactory<Program> とすることで、構成を変更したテスト対象アプリケーションの設定でテストを実行します。

詳細は以下を参照してください。

WebApplicationFactory のカスタマイズ