{"id":"bc7fc5f0-c80e-4d31-b923-6e4064be3ef9","shortId":"7SYcAU","kind":"skill","title":"dotnet-testing-advanced-aspire-testing","tagline":".NET Aspire Testing 整合測試框架完整指南。當需要測試 .NET Aspire 分散式應用程式、設定 AppHost 測試或從 Testcontainers 遷移至 Aspire 測試時使用。涵蓋 DistributedApplicationTestingBuilder、容器生命週期管理、多服務編排、Respawn 配置與時間可測試性設計。\nMake sure to use this skill whenever the user mentions .NET Aspire, AppHost testing, DistributedApp","description":"# .NET Aspire Testing 整合測試框架\n\n## 前置需求\n\n- .NET 8 SDK 或更高版本\n- Docker Desktop（WSL 2 或 Hyper-V）\n- AppHost 專案（.NET Aspire 應用編排）\n\n## 核心概念\n\n### .NET Aspire Testing 定位\n\n**.NET Aspire Testing 是封閉式整合測試框架**，專為分散式應用設計：\n\n- 在測試中重現與正式環境相同的服務架構\n- 使用真實容器而非模擬服務\n- 自動管理容器生命週期\n\n### AppHost 專案的必要性\n\n使用 .NET Aspire Testing 必須建立 AppHost 專案：\n\n- 定義完整的應用架構和容器編排\n- 測試重用 AppHost 配置建立環境\n- 沒有 AppHost 就無法使用 Aspire Testing\n\n### 與 Testcontainers 的差異\n\n| 特性     | .NET Aspire Testing | Testcontainers |\n| -------- | ------------------- | -------------- |\n| 設計目標 | 雲原生分散式應用    | 通用容器測試   |\n| 配置方式 | AppHost 宣告式定義  | 程式碼手動配置 |\n| 服務編排 | 自動處理            | 手動管理       |\n| 學習曲線 | 較高                | 中等           |\n| 適用場景 | 已用 Aspire 的專案  | 傳統 Web API   |\n\n## 專案結構\n\n```text\nMyApp/\n├── src/\n│   ├── MyApp.Api/                    # WebApi 層\n│   ├── MyApp.Application/            # 應用服務層\n│   ├── MyApp.Domain/                 # 領域模型\n│   └── MyApp.Infrastructure/         # 基礎設施層\n├── MyApp.AppHost/                    # Aspire 編排專案 ⭐\n│   ├── MyApp.AppHost.csproj\n│   └── Program.cs\n└── tests/\n    └── MyApp.Tests.Integration/      # Aspire Testing 整合測試\n        ├── MyApp.Tests.Integration.csproj\n        ├── Infrastructure/\n        │   ├── AspireAppFixture.cs\n        │   ├── IntegrationTestCollection.cs\n        │   ├── IntegrationTestBase.cs\n        │   └── DatabaseManager.cs\n        └── Controllers/\n            └── MyControllerTests.cs\n```\n\n## 必要套件\n\n### AppHost 專案\n\n```xml\n<Project Sdk=\"Microsoft.NET.Sdk\">\n  <Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"9.0.0\" />\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net9.0</TargetFramework>\n    <IsAspireHost>true</IsAspireHost>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Hosting.AppHost\" Version=\"9.1.0\" />\n    <PackageReference Include=\"Aspire.Hosting.PostgreSQL\" Version=\"9.1.0\" />\n    <PackageReference Include=\"Aspire.Hosting.Redis\" Version=\"9.1.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\src\\MyApp.Api\\MyApp.Api.csproj\" />\n  </ItemGroup>\n</Project>\n```\n\n### 測試專案\n\n```xml\n<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <IsTestProject>true</IsTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Hosting.Testing\" Version=\"13.1.3\" />\n    <PackageReference Include=\"AwesomeAssertions\" Version=\"9.4.0\" />\n    <PackageReference Include=\"AwesomeAssertions.Web\" Version=\"1.9.6\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Testing\" Version=\"9.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.3.0\" />\n    <PackageReference Include=\"Respawn\" Version=\"7.0.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\MyApp.AppHost\\MyApp.AppHost.csproj\" />\n  </ItemGroup>\n</Project>\n```\n\n## 容器生命週期管理\n\n使用 `ContainerLifetime.Session` 確保測試資源自動清理：\n\n```csharp\nvar postgres = builder.AddPostgres(\"postgres\")\n                     .WithLifetime(ContainerLifetime.Session);\n\nvar redis = builder.AddRedis(\"redis\")\n                  .WithLifetime(ContainerLifetime.Session);\n```\n\n- **Session**：測試會話結束後自動清理（推薦）\n- **Persistent**：容器持續運行，需手動清理\n\n## 等待服務就緒\n\n容器啟動與服務就緒是兩個階段，需要等待機制：\n\n```csharp\nprivate async Task WaitForPostgreSqlReadyAsync()\n{\n    const int maxRetries = 30;\n    const int delayMs = 1000;\n\n    for (int i = 0; i < maxRetries; i++)\n    {\n        try\n        {\n            var connectionString = await GetConnectionStringAsync();\n            await using var connection = new NpgsqlConnection(connectionString);\n            await connection.OpenAsync();\n            return;\n        }\n        catch (Exception ex) when (i < maxRetries - 1)\n        {\n            await Task.Delay(delayMs);\n        }\n    }\n    throw new InvalidOperationException(\"PostgreSQL 服務未能就緒\");\n}\n```\n\n## 資料庫初始化\n\nAspire 啟動容器但不自動建立資料庫：\n\n```csharp\nprivate async Task EnsureDatabaseExistsAsync(string connectionString)\n{\n    var builder = new NpgsqlConnectionStringBuilder(connectionString);\n    var databaseName = builder.Database;\n    builder.Database = \"postgres\"; // 連到預設資料庫\n\n    await using var connection = new NpgsqlConnection(builder.ToString());\n    await connection.OpenAsync();\n\n    var checkDbQuery = $\"SELECT 1 FROM pg_database WHERE datname = '{databaseName}'\";\n    var dbExists = await new NpgsqlCommand(checkDbQuery, connection).ExecuteScalarAsync();\n\n    if (dbExists == null)\n    {\n        await new NpgsqlCommand($\"CREATE DATABASE \\\"{databaseName}\\\"\", connection)\n            .ExecuteNonQueryAsync();\n    }\n}\n```\n\n## Respawn 配置\n\n使用 PostgreSQL 時指定適配器：\n\n```csharp\n_respawner = await Respawner.CreateAsync(connection, new RespawnerOptions\n{\n    TablesToIgnore = new Table[] { \"__EFMigrationsHistory\" },\n    SchemasToInclude = new[] { \"public\" },\n    DbAdapter = DbAdapter.Postgres  // 明確指定（7.0 起可從 DbConnection 自動推斷，但建議保留）\n});\n```\n\n> **Respawn 7.0 升級提示**：\n> - `DbAdapter` 現可從 `DbConnection` 型別自動推斷（使用 `NpgsqlConnection` 時自動選擇 Postgres），但明確指定仍建議以確保正確性\n> - `Microsoft.Data.SqlClient` 不再作為傳遞依賴；若需重置 SQL Server 需自行加入該套件\n> - 新增 SQLite、IBM DB2、Snowflake 適配器支援\n> - 新增 `FormatDeleteStatement` 可自訂刪除語句\n\n## Collection Fixture 最佳實踐\n\n避免每個測試類別重複啟動容器：\n\n```csharp\n[CollectionDefinition(\"Integration Tests\")]\npublic class IntegrationTestCollection : ICollectionFixture<AspireAppFixture>\n{\n}\n\n[Collection(\"Integration Tests\")]\npublic class MyControllerTests : IntegrationTestBase\n{\n    public MyControllerTests(AspireAppFixture fixture) : base(fixture) { }\n}\n```\n\n## 時間可測試性\n\n使用 `TimeProvider` 抽象化時間依賴：\n\n```csharp\n// 服務實作\npublic class ProductService\n{\n    private readonly TimeProvider _timeProvider;\n\n    public ProductService(TimeProvider timeProvider)\n    {\n        _timeProvider = timeProvider;\n    }\n\n    public async Task<Product> CreateAsync(ProductCreateRequest request)\n    {\n        var now = _timeProvider.GetUtcNow();\n        var product = new Product\n        {\n            CreatedAt = now,\n            UpdatedAt = now\n        };\n        // ...\n    }\n}\n\n// DI 註冊\nbuilder.Services.AddSingleton<TimeProvider>(TimeProvider.System);\n```\n\n## 選擇建議\n\n### 選擇 .NET Aspire Testing\n\n- 專案已使用 .NET Aspire\n- 需要測試多服務互動\n- 重視統一的開發測試體驗\n- 雲原生應用架構\n\n### 選擇 Testcontainers\n\n- 傳統 .NET 專案\n- 需要精細的容器控制\n- 與非 .NET 服務整合\n- 團隊對 Aspire 不熟悉\n\n## 常見問題\n\n### 端點配置衝突\n\n不要手動配置已由 Aspire 自動處理的端點：\n\n```csharp\n// ❌ 錯誤：會造成衝突\nbuilder.AddProject<Projects.MyApp_Api>(\"my-api\")\n       .WithHttpEndpoint(port: 8080, name: \"http\");\n\n// ✅ 正確：讓 Aspire 自動處理\nbuilder.AddProject<Projects.MyApp_Api>(\"my-api\")\n       .WithReference(postgresDb)\n       .WithReference(redis);\n```\n\n### Dapper 欄位映射\n\nPostgreSQL snake_case 與 C# PascalCase 的映射：\n\n```csharp\n// 在 Program.cs 初始化\nDapperTypeMapping.Initialize();\n\n// 或使用 SQL 別名\nconst string sql = @\"\n    SELECT id, name, price,\n           created_at AS CreatedAt,\n           updated_at AS UpdatedAt\n    FROM products\";\n```\n\n## 輸出格式\n\n- 產生 AppHost 專案的 `Program.cs`，定義容器編排與服務參考\n- 產生測試基礎設施檔案：`AspireAppFixture.cs`、`IntegrationTestCollection.cs`、`IntegrationTestBase.cs`\n- 產生 `DatabaseManager.cs` 處理資料庫初始化與 Respawn 清理\n- 產生控制器測試類別（`*ControllerTests.cs`），繼承 `IntegrationTestBase`\n- 修改測試專案 `.csproj`，加入 Aspire.Hosting.Testing 與相關套件參考\n\n## 參考資源\n\n### 原始文章\n\n本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章：\n\n- **Day 24 - .NET Aspire Testing 入門基礎介紹**\n  - 鐵人賽文章：https://ithelp.ithome.com.tw/articles/10377071\n  - 範例程式碼：https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day24\n\n- **Day 25 - .NET Aspire 整合測試實戰：從 Testcontainers 到 .NET Aspire Testing**\n  - 鐵人賽文章：https://ithelp.ithome.com.tw/articles/10377197\n  - 範例程式碼：https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day25\n\n### 官方文件\n\n- [.NET Aspire 官方文件](https://learn.microsoft.com/dotnet/aspire/)\n- [Aspire Testing 文件](https://learn.microsoft.com/dotnet/aspire/testing)\n\n### 範例檔案\n\n請參考同目錄下的範例檔案：\n\n- `templates/apphost-program.cs` - AppHost 編排定義\n- `templates/aspire-app-fixture.cs` - 測試基礎設施\n- `templates/integration-test-collection.cs` - Collection Fixture 設定\n- `templates/integration-test-base.cs` - 測試基底類別\n- `templates/database-manager.cs` - 資料庫管理員\n- `templates/controller-tests.cs` - 控制器測試範例\n- `templates/test-project.csproj` - 測試專案設定\n- `templates/apphost-project.csproj` - AppHost 專案設定\n\n### 相關技能\n\n- `dotnet-testing-advanced-testcontainers-database` - Testcontainers 資料庫測試\n- `dotnet-testing-advanced-testcontainers-nosql` - Testcontainers NoSQL 測試\n- `dotnet-testing-advanced-webapi-integration-testing` - 完整 WebAPI 整合測試","tags":["dotnet","testing","advanced","aspire","agent","skills","kevintsengtw","agent-skills","ai-assisted-development","copilot-skills","csharp","dotnet-testing"],"capabilities":["skill","source-kevintsengtw","skill-dotnet-testing-advanced-aspire-testing","topic-agent-skills","topic-ai-assisted-development","topic-copilot-skills","topic-csharp","topic-dotnet","topic-dotnet-testing","topic-github-copilot","topic-integration-testing","topic-testing","topic-unit-testing","topic-xunit"],"categories":["dotnet-testing-agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-advanced-aspire-testing","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add kevintsengtw/dotnet-testing-agent-skills","source_repo":"https://github.com/kevintsengtw/dotnet-testing-agent-skills","install_from":"skills.sh"}},"qualityScore":"0.461","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 23 github stars · SKILL.md body (8,486 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-24T13:02:25.118Z","embedding":null,"createdAt":"2026-04-18T23:04:15.405Z","updatedAt":"2026-04-24T13:02:25.118Z","lastSeenAt":"2026-04-24T13:02:25.118Z","tsv":"'/articles/10377071':546 '/articles/10377197':565 '/dotnet/aspire/)':576 '/dotnet/aspire/testing)':582 '/kevintsengtw/30days_in_testing_samples/tree/main/day24':550 '/kevintsengtw/30days_in_testing_samples/tree/main/day25':569 '0':208 '1':233,275 '1000':204 '2':55 '24':538 '25':552 '30':200,534 '7.0':323,329 '8':49 '8080':457 'advanc':4,609,617,626 'api':123,454,467 'apphost':16,40,60,78,85,89,92,108,156,508,586,603 'aspir':5,8,13,20,39,44,63,67,71,82,94,101,119,138,144,243,423,427,441,446,462,540,554,560,572,577 'aspire.hosting.testing':528 'aspireappfixtur':376 'aspireappfixture.cs':149,513 'async':194,247,400 'await':215,217,224,234,263,270,284,293,308 'base':378 'builder':253 'builder.addpostgres':173 'builder.addproject':451,464 'builder.addredis':179 'builder.database':259,260 'builder.services.addsingleton':418 'builder.tostring':269 'c':478 'case':476 'catch':227 'checkdbqueri':273,287 'class':364,371,387 'collect':355,367,591 'collectiondefinit':360 'connect':220,266,288,299,310 'connection.openasync':225,271 'connectionstr':214,223,251,256 'const':197,201,489 'containerlifetime.session':168,176,182 'control':153 'controllertests.cs':522 'creat':296,496 'createasync':402 'createdat':412,499 'csharp':170,192,245,306,359,384,448,481 'csproj':526 'dapper':472 'dappertypemapping.initialize':485 'databas':278,297,611 'databasemanager.cs':152,517 'databasenam':258,281,298 'datnam':280 'day':537,551 'db2':349 'dbadapt':320,331 'dbadapter.postgres':321 'dbconnect':325,333 'dbexist':283,291 'delaym':203,236 'desktop':53 'di':416 'distributedapp':42 'distributedapplicationtestingbuild':23 'docker':52 'dotnet':2,607,615,624 'dotnet-testing-advanced-aspire-test':1 'dotnet-testing-advanced-testcontainers-databas':606 'dotnet-testing-advanced-testcontainers-nosql':614 'dotnet-testing-advanced-webapi-integration-test':623 'efmigrationshistori':316 'ensuredatabaseexistsasync':249 'ex':229 'except':228 'exe':159 'executenonqueryasync':300 'executescalarasync':289 'fixtur':356,377,379,592 'formatdeletestat':353 'getconnectionstringasync':216 'github.com':549,568 'github.com/kevintsengtw/30days_in_testing_samples/tree/main/day24':548 'github.com/kevintsengtw/30days_in_testing_samples/tree/main/day25':567 'http':459 'hyper':58 'hyper-v':57 'ibm':348 'icollectionfixtur':366 'id':493 'infrastructur':148 'int':198,202,206 'integr':361,368,628 'integrationtestbas':373,524 'integrationtestbase.cs':151,515 'integrationtestcollect':365 'integrationtestcollection.cs':150,514 'invalidoperationexcept':239 'ithelp.ithome.com.tw':545,564 'ithelp.ithome.com.tw/articles/10377071':544 'ithelp.ithome.com.tw/articles/10377197':563 'learn.microsoft.com':575,581 'learn.microsoft.com/dotnet/aspire/)':574 'learn.microsoft.com/dotnet/aspire/testing)':580 'make':28 'maxretri':199,210,232 'mention':37 'microsoft.data.sqlclient':340 'my-api':452,465 'myapp':126 'myapp.api':128 'myapp.apphost':137 'myapp.apphost.csproj':140 'myapp.application':131 'myapp.domain':133 'myapp.infrastructure':135 'myapp.tests.integration':143 'myapp.tests.integration.csproj':147 'mycontrollertest':372,375 'mycontrollertests.cs':154 'name':458,494 'net':7,12,38,43,48,62,66,70,81,100,422,426,434,438,539,553,559,571 'net9.0':160,164 'new':221,238,254,267,285,294,311,314,318,410 'nosql':619,621 'npgsqlcommand':286,295 'npgsqlconnect':222,268,336 'npgsqlconnectionstringbuild':255 'null':292 'pascalcas':479 'persist':186 'pg':277 'port':456 'postgr':172,174,261,338 'postgresdb':469 'postgresql':240,304,474 'price':495 'privat':193,246,389 'product':409,411,505 'productcreaterequest':403 'productservic':388,394 'program.cs':141,483,510 'public':319,363,370,374,386,393,399 'readon':390 'redi':178,180,471 'request':404 'respawn':26,301,307,328,519 'respawner.createasync':309 'respawneropt':312 'return':226 'schemastoinclud':317 'sdk':50 'select':274,492 'server':344 'session':183 'skill':33 'skill-dotnet-testing-advanced-aspire-testing' 'snake':475 'snowflak':350 'source-kevintsengtw' 'sql':343,487,491 'sqlite':347 'src':127 'string':250,490 'sure':29 'tabl':315 'tablestoignor':313 'task':195,248,401 'task.delay':235 'templates/apphost-program.cs':585 'templates/apphost-project.csproj':602 'templates/aspire-app-fixture.cs':588 'templates/controller-tests.cs':598 'templates/database-manager.cs':596 'templates/integration-test-base.cs':594 'templates/integration-test-collection.cs':590 'templates/test-project.csproj':600 'test':3,6,9,41,45,68,72,83,95,102,142,145,362,369,424,541,561,578,608,616,625,629 'testcontain':18,97,103,432,557,610,612,618,620 'text':125 'throw':237 'timeprovid':382,391,392,395,396,397,398 'timeprovider.getutcnow':407 'timeprovider.system':419 'topic-agent-skills' 'topic-ai-assisted-development' 'topic-copilot-skills' 'topic-csharp' 'topic-dotnet' 'topic-dotnet-testing' 'topic-github-copilot' 'topic-integration-testing' 'topic-testing' 'topic-unit-testing' 'topic-xunit' 'tri':212 'true':161,165 'updat':500 'updatedat':414,503 'use':31,218,264 'user':36 'v':59 'var':171,177,213,219,252,257,265,272,282,405,408 'waitforpostgresqlreadyasync':196 'web':122 'webapi':129,627,631 'whenev':34 'withhttpendpoint':455 'withlifetim':175,181 'withrefer':468,470 'wsl':54 'xml':158,163 '不再作為傳遞依賴':341 '不熟悉':442 '不要手動配置已由':445 '中等':116 '但建議保留':327 '但明確指定仍建議以確保正確性':339 '使用':80,167,303,335,381 '使用真實容器而非模擬服務':76 '修改測試專案':525 '傳統':121,433 '入門基礎介紹':542 '分散式應用程式':14 '初始化':484 '別名':488 '到':558 '前置需求':47 '加入':527 '升級提示':330 '原始文章':531 '參考資源':530 '可自訂刪除語句':354 '啟動容器但不自動建立資料庫':244 '團隊對':440 '在':482 '在測試中重現與正式環境相同的服務架構':75 '型別自動推斷':334 '基礎設施層':136 '多服務編排':25 '天挑戰':535 '學習曲線':114 '完整':630 '官方文件':570,573 '定位':69 '定義完整的應用架構和容器編排':87 '定義容器編排與服務參考':511 '宣告式定義':109 '容器啟動與服務就緒是兩個階段':190 '容器持續運行':187 '容器生命週期管理':24,166 '專案':61,86,157,435 '專案已使用':425 '專案的':509 '專案的必要性':79 '專案結構':124 '專案設定':604 '專為分散式應用設計':74 '就無法使用':93 '層':130 '已用':118 '常見問題':443 '從':556 '必要套件':155 '必須建立':84 '應用服務層':132 '應用編排':64 '或':56 '或使用':486 '或更高版本':51 '手動管理':113 '抽象化時間依賴':383 '控制器測試範例':599 '推薦':185 '整合測試':146,632 '整合測試實戰':555 '整合測試框架':46 '整合測試框架完整指南':10 '文件':579 '新增':346,352 '明確指定':322 '是封閉式整合測試框架':73 '時指定適配器':305 '時自動選擇':337 '時間可測試性':380 '最佳實踐':357 '會造成衝突':450 '服務實作':385 '服務整合':439 '服務未能就緒':241 '服務編排':111 '本技能內容提煉自':532 '核心概念':65 '欄位映射':473 '正確':460 '沒有':91 '涵蓋':22 '清理':520 '測試':622 '測試基底類別':595 '測試基礎設施':589 '測試專案':162 '測試專案設定':601 '測試或從':17 '測試時使用':21 '測試會話結束後自動清理':184 '測試重用':88 '特性':99 '現可從':332 '產生':507,516 '產生控制器測試類別':521 '產生測試基礎設施檔案':512 '當需要測試':11 '的專案':120 '的差異':98 '的映射':480 '相關技能':605 '確保測試資源自動清理':169 '程式碼手動配置':110 '端點配置衝突':444 '等待服務就緒':189 '範例檔案':583 '範例程式碼':547,566 '系列文章':536 '編排定義':587 '編排專案':139 '繼承':523 '老派軟體工程師的測試修練':533 '自動推斷':326 '自動管理容器生命週期':77 '自動處理':112,463 '自動處理的端點':447 '與':96,477 '與相關套件參考':529 '與非':437 '若需重置':342 '處理資料庫初始化與':518 '設定':15,593 '設計目標':104 '註冊':417 '請參考同目錄下的範例檔案':584 '讓':461 '資料庫初始化':242 '資料庫測試':613 '資料庫管理員':597 '起可從':324 '較高':115 '輸出格式':506 '通用容器測試':106 '連到預設資料庫':262 '適用場景':117 '適配器支援':351 '遷移至':19 '選擇':421,431 '選擇建議':420 '避免每個測試類別重複啟動容器':358 '配置':302 '配置建立環境':90 '配置方式':107 '配置與時間可測試性設計':27 '重視統一的開發測試體驗':429 '錯誤':449 '鐵人賽文章':543,562 '雲原生分散式應用':105 '雲原生應用架構':430 '需手動清理':188 '需自行加入該套件':345 '需要測試多服務互動':428 '需要等待機制':191 '需要精細的容器控制':436 '領域模型':134","prices":[{"id":"52391638-f6ad-4d50-b1dc-3e8b0b00bcb6","listingId":"bc7fc5f0-c80e-4d31-b923-6e4064be3ef9","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"kevintsengtw","category":"dotnet-testing-agent-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T23:04:15.405Z"}],"sources":[{"listingId":"bc7fc5f0-c80e-4d31-b923-6e4064be3ef9","source":"github","sourceId":"kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-advanced-aspire-testing","sourceUrl":"https://github.com/kevintsengtw/dotnet-testing-agent-skills/tree/main/skills/dotnet-testing-advanced-aspire-testing","isPrimary":false,"firstSeenAt":"2026-04-18T23:04:15.405Z","lastSeenAt":"2026-04-24T13:02:25.118Z"}],"details":{"listingId":"bc7fc5f0-c80e-4d31-b923-6e4064be3ef9","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"kevintsengtw","slug":"dotnet-testing-advanced-aspire-testing","github":{"repo":"kevintsengtw/dotnet-testing-agent-skills","stars":23,"topics":["agent-skills","ai-assisted-development","copilot-skills","csharp","dotnet","dotnet-testing","github-copilot","integration-testing","testing","unit-testing","xunit"],"license":"mit","html_url":"https://github.com/kevintsengtw/dotnet-testing-agent-skills","pushed_at":"2026-03-31T07:28:56Z","description":"AI Agent Skills for .NET Testing - Based on 30-Day Testing Challenge (iThome Ironman 2025 Winner)","skill_md_sha":"550aded42ef69366e406b3403ea7823daa13fd2a","skill_md_path":"skills/dotnet-testing-advanced-aspire-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/kevintsengtw/dotnet-testing-agent-skills/tree/main/skills/dotnet-testing-advanced-aspire-testing"},"layout":"multi","source":"github","category":"dotnet-testing-agent-skills","frontmatter":{"name":"dotnet-testing-advanced-aspire-testing","description":".NET Aspire Testing 整合測試框架完整指南。當需要測試 .NET Aspire 分散式應用程式、設定 AppHost 測試或從 Testcontainers 遷移至 Aspire 測試時使用。涵蓋 DistributedApplicationTestingBuilder、容器生命週期管理、多服務編排、Respawn 配置與時間可測試性設計。\nMake sure to use this skill whenever the user mentions .NET Aspire, AppHost testing, DistributedApplicationTestingBuilder, cloud-native testing, or migrating from Testcontainers to Aspire, even if they don't explicitly ask for Aspire testing guidance.\nKeywords: aspire testing, .NET Aspire, DistributedApplicationTestingBuilder, AppHost testing, 分散式測試, AspireAppFixture, IAsyncLifetime, ContainerLifetime.Session, 雲原生測試, 多服務整合, Aspire.Hosting.Testing, Respawn"},"skills_sh_url":"https://skills.sh/kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-advanced-aspire-testing"},"updatedAt":"2026-04-24T13:02:25.118Z"}}