xiaohongshu
xiaohongshu
dotnet-testing-advanced-aspire-testing
.NET Aspire Testing 整合測試框架完整指南。涵蓋 AppHost 專案設定、DistributedApplicationTestingBuilder、容器生命週期管理。包含從 Testcontainers 遷移、多服務編排、Respawn 配置與時間可測試性設計。 Keywords: aspire testing, .NET Aspire, DistributedApplicationTestingBuilder, AppHost testing, 分散式測試, AspireAppFixture, IAsyncLifetime, ContainerLifetime.Se...
Full skill instructions
當被要求執行以下任務時,請使用此技能:
.NET Aspire Testing 是封閉式整合測試框架,專為分散式應用設計:
使用 .NET Aspire Testing 必須建立 AppHost 專案:
| 特性 | .NET Aspire Testing | Testcontainers |
|---|---|---|
| 設計目標 | 雲原生分散式應用 | 通用容器測試 |
| 配置方式 | AppHost 宣告式定義 | 程式碼手動配置 |
| 服務編排 | 自動處理 | 手動管理 |
| 學習曲線 | 較高 | 中等 |
| 適用場景 | 已用 Aspire 的專案 | 傳統 Web API |
MyApp/
├── src/
│ ├── MyApp.Api/ # WebApi 層
│ ├── MyApp.Application/ # 應用服務層
│ ├── MyApp.Domain/ # 領域模型
│ └── MyApp.Infrastructure/ # 基礎設施層
├── MyApp.AppHost/ # Aspire 編排專案 ⭐
│ ├── MyApp.AppHost.csproj
│ └── Program.cs
└── tests/
└── MyApp.Tests.Integration/ # Aspire Testing 整合測試
├── MyApp.Tests.Integration.csproj
├── Infrastructure/
│ ├── AspireAppFixture.cs
│ ├── IntegrationTestCollection.cs
│ ├── IntegrationTestBase.cs
│ └── DatabaseManager.cs
└── Controllers/
└── MyControllerTests.cs
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.0" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\MyApp.Api\MyApp.Api.csproj" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.1.0" />
<PackageReference Include="AwesomeAssertions" Version="9.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Respawn" Version="6.2.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MyApp.AppHost\MyApp.AppHost.csproj" />
</ItemGroup>
</Project>
使用 ContainerLifetime.Session 確保測試資源自動清理:
var postgres = builder.AddPostgres("postgres")
.WithLifetime(ContainerLifetime.Session);
var redis = builder.AddRedis("redis")
.WithLifetime(ContainerLifetime.Session);
容器啟動與服務就緒是兩個階段,需要等待機制:
private async Task WaitForPostgreSqlReadyAsync()
{
const int maxRetries = 30;
const int delayMs = 1000;
for (int i = 0; i < maxRetries; i++)
{
try
{
var connectionString = await GetConnectionStringAsync();
await using var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();
return;
}
catch (Exception ex) when (i < maxRetries - 1)
{
await Task.Delay(delayMs);
}
}
throw new InvalidOperationException("PostgreSQL 服務未能就緒");
}
Aspire 啟動容器但不自動建立資料庫:
private async Task EnsureDatabaseExistsAsync(string connectionString)
{
var builder = new NpgsqlConnectionStringBuilder(connectionString);
var databaseName = builder.Database;
builder.Database = "postgres"; // 連到預設資料庫
await using var connection = new NpgsqlConnection(builder.ToString());
await connection.OpenAsync();
var checkDbQuery = $"SELECT 1 FROM pg_database WHERE datname = '{databaseName}'";
var dbExists = await new NpgsqlCommand(checkDbQuery, connection).ExecuteScalarAsync();
if (dbExists == null)
{
await new NpgsqlCommand($"CREATE DATABASE \"{databaseName}\"", connection)
.ExecuteNonQueryAsync();
}
}
使用 PostgreSQL 時必須指定適配器:
_respawner = await Respawner.CreateAsync(connection, new RespawnerOptions
{
TablesToIgnore = new Table[] { "__EFMigrationsHistory" },
SchemasToInclude = new[] { "public" },
DbAdapter = DbAdapter.Postgres // 關鍵!
});
避免每個測試類別重複啟動容器:
[CollectionDefinition("Integration Tests")]
public class IntegrationTestCollection : ICollectionFixture<AspireAppFixture>
{
}
[Collection("Integration Tests")]
public class MyControllerTests : IntegrationTestBase
{
public MyControllerTests(AspireAppFixture fixture) : base(fixture) { }
}
使用 TimeProvider 抽象化時間依賴:
// 服務實作
public class ProductService
{
private readonly TimeProvider _timeProvider;
public ProductService(TimeProvider timeProvider)
{
_timeProvider = timeProvider;
}
public async Task<Product> CreateAsync(ProductCreateRequest request)
{
var now = _timeProvider.GetUtcNow();
var product = new Product
{
CreatedAt = now,
UpdatedAt = now
};
// ...
}
}
// DI 註冊
builder.Services.AddSingleton<TimeProvider>(TimeProvider.System);
不要手動配置已由 Aspire 自動處理的端點:
// ❌ 錯誤:會造成衝突
builder.AddProject<Projects.MyApp_Api>("my-api")
.WithHttpEndpoint(port: 8080, name: "http");
// ✅ 正確:讓 Aspire 自動處理
builder.AddProject<Projects.MyApp_Api>("my-api")
.WithReference(postgresDb)
.WithReference(redis);
PostgreSQL snake_case 與 C# PascalCase 的映射:
// 在 Program.cs 初始化
DapperTypeMapping.Initialize();
// 或使用 SQL 別名
const string sql = @"
SELECT id, name, price,
created_at AS CreatedAt,
updated_at AS UpdatedAt
FROM products";
本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
Day 24 - .NET Aspire Testing 入門基礎介紹
Day 25 - .NET Aspire 整合測試實戰:從 Testcontainers 到 .NET Aspire Testing
請參考同目錄下的範例檔案:
templates/apphost-program.cs - AppHost 編排定義templates/aspire-app-fixture.cs - 測試基礎設施templates/integration-test-collection.cs - Collection Fixture 設定templates/integration-test-base.cs - 測試基底類別templates/database-manager.cs - 資料庫管理員templates/controller-tests.cs - 控制器測試範例templates/test-project.csproj - 測試專案設定templates/apphost-project.csproj - AppHost 專案設定xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience