ASP.NET Core Web アプリケーションのテスト
コードを入手する
このガイドでは、以下の内容を学びます:
-
Testcontainers を使用してテスト依存関係を起動する方法
-
SQLite を Microsoft SQL Server に置き換える方法
前提条件
-
Testcontainers は Docker-API 互換のコンテナランタイムを必要とします。
-
このガイドは、Microsoft の「ASP.NET Core における統合テスト 」を基に作成されています。Microsoft のコードサンプルはこちら から確認できます。このガイドで学ぶ内容は、参照元のコードを基にした追加的な内容です。
このガイドで達成すること
以下のセクションでは、SQLite を本番環境で使用されるデータベースプロバイダーに置き換える方法を説明します。これにより、テストへの信頼性を向上させ、実際の環境に近い環境でテストを実行できるようになります。
はじめる
tests/RazorPagesProject.Tests
ディレクトリに移動し、以下の NuGet パッケージをインストールします:
Microsoft.EntityFrameworkCore.SqlServer
Testcontainers.MsSql
cd AspNetCore.Docs.Samples/test/integration-tests/IntegrationTestsSample/tests/RazorPagesProject.Tests
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 7.0.0
dotnet add package Testcontainers.MsSql --version 3.0.0
Testcontainers for .NET は、ベストプラクティスに基づいた設定を備えたさまざまなモジュール を提供しています。
これで依存関係の設定が完了したので、プロジェクトに新しいテストクラスを追加できます。まず、Microsoft SQL Server の依存コンテナを設定、作成、起動する責任を持つ MsSqlTests
クラスを作成します。この MsSqlTests
クラスには、テストを実行するためのネストされた IndexPageTests
クラスを含めます。この構造により、テストクラス内でプライベートなコンテナフィールドにアクセスできるようになり、テストエクスプローラー内で整理された階層を保つことができます。
public sealed class MsSqlTests : IAsyncLifetime
{
private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder().Build();
public Task InitializeAsync()
{
return _msSqlContainer.StartAsync();
}
public Task DisposeAsync()
{
return _msSqlContainer.DisposeAsync().AsTask();
}
public sealed class IndexPageTests : IClassFixture<MsSqlTests>, IDisposable
{
private readonly WebApplicationFactory<Program> _webApplicationFactory;
private readonly HttpClient _httpClient;
public IndexPageTests(MsSqlTests fixture)
{
var clientOptions = new WebApplicationFactoryClientOptions();
clientOptions.AllowAutoRedirect = false;
_webApplicationFactory = new CustomWebApplicationFactory(fixture);
_httpClient = _webApplicationFactory.CreateClient(clientOptions);
}
public void Dispose()
{
_webApplicationFactory.Dispose();
}
private sealed class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
private readonly string _connectionString;
public CustomWebApplicationFactory(MsSqlTests fixture)
{
_connectionString = fixture._msSqlContainer.GetConnectionString();
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services.Remove(services.SingleOrDefault(service => typeof(DbContextOptions<ApplicationDbContext>) == service.ServiceType));
services.Remove(services.SingleOrDefault(service => typeof(DbConnection) == service.ServiceType));
services.AddDbContext<ApplicationDbContext>((_, option) => option.UseSqlServer(_connectionString));
});
}
}
}
}
Microsoft SQL Server の Docker イメージは、Apple Silicon を搭載した Mac などの ARM デバイスでは互換性がありません。その代わりに、SqlEdge モジュールや Testcontainers Cloud を使用することができます。
Testcontainers モジュールはあらかじめ設定済みで、多くの開発者に認識されたベストプラクティスに従っています。通常、モジュールの設定を自分で行う必要はありません。次のように新しいコンテナインスタンスを作成するだけです:
new MsSqlBuilder().Build();
しかし、一部のケースでは独自の設定を使用する必要がある場合があります。そのような場合、Testcontainers は汎用ビルダー ContainerBuilder()
を提供しています。
xUnit.net はクラスが作成された直後に IAsyncLifetime.InitializeAsync
を呼び出します。このメカニズムを使用して、テストの実行前に Microsoft SQL Server インスタンスを起動します。
IndexPageTests
クラスでは、WebApplicationFactory<TEntryPoint>
のカスタムインスタンスを作成します。SQLite に依存するデータベースコンテキストを追加する代わりに、Microsoft SQL Server の接続文字列を UseSqlServer(string)
に渡して新しいデータベースコンテキストを追加します。Testcontainers を使用すれば、この設定全体を Web アプリケーションのエントリポイントクラスに移動し、アプリケーションの起動と同時に依存サービスを開始することも可能です。
これでテストクラスが準備できたので、元のテストをこのクラスに移動できます。例えば、以下のテストを新しい IndexPageTests
クラスにコピーし、Microsoft SQL Server インスタンスに対してテストを実行します:
[Fact]
public async Task Post_DeleteAllMessagesHandler_ReturnsRedirectToRoot()
{
// Arrange
var defaultPage = await _httpClient.GetAsync("/")
.ConfigureAwait(false);
var document = await HtmlHelpers.GetDocumentAsync(defaultPage)
.ConfigureAwait(false);
// Act
var form = (IHtmlFormElement)document.QuerySelector("form[id='messages']");
var submitButton = (IHtmlButtonElement)document.QuerySelector("button[id='deleteAllBtn']");
var response = await _httpClient.SendAsync(form, submitButton)
.ConfigureAwait(false);
// Assert
Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode);
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/", response.Headers.Location.OriginalString);
}
最初のテスト実行時は、必要なイメージをプルする必要があるため、数秒余分に時間がかかる場合があることに注意してください。
まとめ
SQLite を本番環境で使用されるデータベースプロバイダーに置き換えることで、開発者はテストに対する信頼性をさらに高めることができます。MsSqlTests
クラスは Testcontainers を使用して Microsoft SQL Server コンテナを設定、作成、起動し、IndexPageTests
クラスで実際のデータベースを用いたテストを実行できるようにします。このアプローチにより、開発者は本番に近い環境でアプリケーションをテストでき、開発サイクルの初期段階で問題を特定するのに役立ちます。
Testcontainers の詳細については、https://testcontainers.com をご覧ください。