aspire-integration-testing について
.NET Aspire を使う開発者向けに、ASP.NET Core アプリや分散サービスの xUnit 統合テストを解説するスキルです。実際のインフラ、動的なエンドポイント検出、ヘルスチェックを使うテスト方法を扱います。
主な機能
- 01Aspire によるテストサービスの起動
- 02IAsyncLifetime によるフィクスチャ管理
- 03サービスエンドポイントの動的検出
- 04実データベースとコンテナーインフラの利用
- 05Playwright とメッセージキューのテスト
活用シーン
- 01ASP.NET Core とデータベースの連携をテスト
- 02マイクロサービス間通信を検証
- 03実バックエンドを使った UI テスト
MCP 対応
Aspire CLI と MCP の連携について触れており、AI アシスタントから実行中のアプリケーション状態を照会できます。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ aaronontheweb/ dotnet-skills --skill aspire-integration-testingインストール後、Claude Code で/aspire-integration-testingを入力して読み込まれたか確認します。
同梱ファイルadvanced-patterns.mdci-and-tooling.md
詳細
.NET Aspire + xUnit による統合テスト
このスキルを使用するタイミング
次のような場合にこのスキルを使用します。
- .NET Aspire アプリケーションの統合テストを作成する
- 実際のデータベース接続を使用して ASP.NET Core アプリをテストする
- 分散アプリケーションにおけるサービス間通信を検証する
- コンテナー内の実際のインフラストラクチャ(SQL Server、Redis、メッセージキュー)を使用してテストする
- Aspire がオーケストレーションするサービスと Playwright の UI テストを組み合わせる
- 適切なサービス検出とネットワークを使用してマイクロサービスをテストする
参照ファイル
- advanced-patterns.md:エンドポイント検出、データベーステスト、Playwright、条件付き構成、Respawn、サービス通信、メッセージキュー
- ci-and-tooling.md:CI/CD 統合、カスタムリソース待機処理、MCP を使用した Aspire CLI
基本原則
- 実際の依存関係 - モックではなく、Aspire 経由で実際のインフラストラクチャ(データベース、キャッシュ)を使用します
- 動的なポートバインド - 競合を避けるため、Aspire にポートを動的に割り当てさせます(
127.0.0.1:0) - フィクスチャのライフサイクル - 適切なテストフィクスチャのセットアップと終了処理には
IAsyncLifetimeを使用します - エンドポイント検出 - URL をハードコーディングせず、実行時に Aspire からエンドポイントを検出します
- 並列実行の分離 - xUnit コレクションを使用してテストの並列実行を制御します
- ヘルスチェック - テストの実行前に、必ずサービスが正常な状態になるまで待機します
テストアーキテクチャの概要
┌─────────────────┐ ┌──────────────────────┐
│ xUnit test file │──uses────────────►│ AspireFixture │
└─────────────────┘ │ (IAsyncLifetime) │
└──────────────────────┘
│
│ starts
▼
┌───────────────────────────┐
│ DistributedApplication │
│ (from AppHost) │
└───────────────────────────┘
│ exposes
▼
┌──────────────────────────────┐
│ Dynamic HTTP Endpoints │
└──────────────────────────────┘
│ consumed by
▼
┌─────────────────────────┐
│ HttpClient / Playwright│
└─────────────────────────┘
必須の NuGet パッケージ
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />
<PackageReference Include="xunit" Version="*" />
<PackageReference Include="xunit.runner.visualstudio" Version="*" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" />
</ItemGroup>
重要:統合テストでのファイルウォッチャーの修正
多くの統合テストを実行し、それぞれが IHost を起動する場合、既定の .NET ホストビルダーは構成の再読み込み用にファイルウォッチャーを有効にします。これにより、Linux でファイルディスクリプターの上限に達します。
テストを実行する前に、これをテストプロジェクトに追加してください:
// TestEnvironmentInitializer.cs
using System.Runtime.CompilerServices;
namespace YourApp.Tests;
internal static class TestEnvironmentInitializer
{
[ModuleInitializer]
internal static void Initialize()
{
// Disable config file watching in test hosts
// Prevents file descriptor exhaustion (inotify watch limit) on Linux
Environment.SetEnvironmentVariable("DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE", "false");
}
}
パターン 1:基本的な Aspire テストフィクスチャ(最新 API)
using Aspire.Hosting;
using Aspire.Hosting.Testing;
public sealed class AspireAppFixture : IAsyncLifetime
{
private DistributedApplication? _app;
public DistributedApplication App => _app
?? throw new InvalidOperationException("App not initialized");
public async Task InitializeAsync()
{
var builder = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.YourApp_AppHost>([
"YourApp:UseVolumes=false",
"YourApp:Environment=IntegrationTest",
"YourApp:Replicas=1"
]);
_app = await builder.BuildAsync();
using var startupCts = new CancellationTokenSource(TimeSpan.FromMinutes(10));
await _app.StartAsync(startupCts.Token);
using var healthCts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
await _app.ResourceNotifications.WaitForResourceHealthyAsync("api", healthCts.Token);
}
public Uri GetEndpoint(string resourceName, string scheme = "https")
{
return _app?.GetEndpoint(resourceName, scheme)
?? throw new InvalidOperationException($"Endpoint for '{resourceName}' not found");
}
public async Task DisposeAsync()
{
if (_app is not null)
{
await _app.DisposeAsync();
}
}
}
パターン 2:テストでフィクスチャを使用する
[CollectionDefinition("Aspire collection")]
public class AspireCollection : ICollectionFixture<AspireAppFixture> { }
[Collection("Aspire collection")]
public class IntegrationTests
{
private readonly AspireAppFixture _fixture;
public IntegrationTests(AspireAppFixture fixture)
{
_fixture = fixture;
}
[Fact]
public async Task Application_ShouldStart()
{
var httpClient = _fixture.App.CreateHttpClient("yourapp");
var response = await httpClient.GetAsync("/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
エンドポイント検出、データベーステスト、Playwright UI テスト、条件付きリソース構成、Respawn によるデータベースのリセット、サービス間通信、メッセージキューのテストパターンについては、advanced-patterns.md を参照してください。
よく使われるパターンの概要
| パターン | 使用例 |
|---|---|
| 基本的なフィクスチャ | シンプルな HTTP エンドポイントのテスト |
| エンドポイント検出 | URL のハードコーディングを回避 |
| データベーステスト | データアクセス層を検証 |
| Playwright 統合 | 実際のバックエンドを使用した UI の完全なテスト |
| 構成の上書き | テスト固有の設定 |
| ヘルスチェック | サービスの準備完了を確認 |
| サービス間通信 | 分散システムの連携をテスト |
| メッセージキューのテスト | 非同期メッセージングを検証 |
わかりにくいヒント・注意点
| 問題 | 解決策 |
|---|---|
| テストがすぐにタイムアウトする | await _app.StartAsync() を呼び出し、サービスが正常な状態になるまで待機します |
| テスト間でポートが競合する | xUnit の CollectionDefinition を使用してフィクスチャを共有します |
| タイミングが原因でテストが不安定になる | Task.Delay() ではなく、適切なヘルスチェックのポーリングを実装します |
| SQL Server に接続できない | GetConnectionStringAsync() を使用して接続文字列を動的に取得します |
| 並列テストが互いに干渉する | [Collection] 属性を使用して、関連するテストを順次実行します |
| Aspire ダッシュボードが競合する | ダッシュボードは同時に 1 つだけ実行できます。テストでは同じインスタンスを再利用します |
ベストプラクティス
IAsyncLifetimeを使用する - 非同期の初期化とクリーンアップを適切に行えます- コレクションでフィクスチャを共有する - アプリのインスタンスを再利用してテストの実行時間を短縮できます
- エンドポイントを動的に検出する - localhost:5000 などをハードコーディングしないでください
- ヘルスチェックを待つ - サービスがすぐに準備完了になると想定しないでください
- 実際の依存関係を使ってテストする - Aspire を使えば、実際の SQL、Redis などを簡単に利用できます
- リソースをクリーンアップする -
DisposeAsyncを必ず適切に実装してください - 意味のあるテストデータを使う - 現実的なテストデータをデータベースにシードしてください
- 失敗するシナリオをテストする - エラー処理と回復性を検証してください
- テストを分離する - 各テストは独立し、実行順序に依存しないようにしてください
- テストの実行時間を監視する - テストが遅い場合は、並列化を検討してください
GitHub Actions のセットアップ、カスタムリソース待機処理、Aspire CLI/MCP 統合については、ci-and-tooling.md を参照してください。
デバッグのヒント
- Aspire Dashboard を実行する - テストが失敗したら、
http://localhost:15888のダッシュボードを確認してください - MCP で Aspire CLI を使う - AI アシスタントに実際のアプリケーション状態を照会させます
- 詳細なログを有効にする - より詳細な出力を得るには、
ASPIRE_ALLOW_UNSECURED_TRANSPORT=trueを設定してください - コンテナーのログを確認する -
docker logsを使ってコンテナーの出力を調べてください - フィクスチャにブレークポイントを設定する - フィクスチャの初期化をデバッグして、起動時の問題を特定してください
- リソース名を確認する - AppHost とテストでリソース名が一致していることを確認してください
コメント
Markdown 対応