{"id":"149fb0b7-705c-431a-8dfa-95e95a663b6d","shortId":"ZZWy5k","kind":"skill","title":"dotnet-testing-advanced-webapi-integration-testing","tagline":"ASP.NET Core WebApi 整合測試完整指南。當需要對 WebApi 端點進行整合測試或驗證 ProblemDetails 錯誤格式時使用。涵蓋 WebApplicationFactory、IExceptionHandler、Testcontainers 多容器編排、Flurl URL 建構與 AwesomeAssertions HTTP 驗證。\nMake sure to use this skill whenever the user mentions WebApi integration testing, ProblemDetails, ","description":"# WebApi 整合測試\n\n## 學習目標\n\n完成本技能學習後，您將能夠：\n\n1. 建立完整的 WebApi 整合測試架構\n2. 使用 `IExceptionHandler` 實作現代化異常處理\n3. 驗證 `ProblemDetails` 和 `ValidationProblemDetails` 標準格式\n4. 使用 Flurl 簡化 HTTP 測試的 URL 建構\n5. 使用 AwesomeAssertions 進行精確的 HTTP 回應驗證\n6. 建立多容器 (PostgreSQL + Redis) 測試環境\n\n## 核心概念\n\n### IExceptionHandler - 現代化異常處理\n\nASP.NET Core 8+ 引入的 `IExceptionHandler` 介面提供了比傳統 middleware 更優雅的錯誤處理方式。`GlobalExceptionHandler` 依據例外類型（KeyNotFoundException → 404、ArgumentException → 400、其他 → 500）產生對應的 `ProblemDetails` 回應。\n\n### ProblemDetails 標準格式\n\nRFC 7807 定義的統一錯誤回應格式：\n\n| 欄位       | 說明               |\n| ---------- | ------------------ |\n| `type`     | 問題類型的 URI     |\n| `title`    | 簡短的錯誤描述     |\n| `status`   | HTTP 狀態碼        |\n| `detail`   | 詳細的錯誤說明     |\n| `instance` | 發生問題的實例 URI |\n\n### ValidationProblemDetails - 驗證錯誤專用\n\n繼承自 ProblemDetails，額外包含 `errors` 字典，記錄每個欄位的驗證錯誤訊息。\n\n### FluentValidation 異常處理器\n\nFluentValidation 異常處理器實作 `IExceptionHandler` 介面，專門處理 `ValidationException`，將驗證錯誤轉換為標準的 `ValidationProblemDetails` 格式回應。處理器之間按照註冊順序執行，特定處理器（如 FluentValidation）必須在全域處理器之前註冊。\n\n> 完整實作程式碼請參閱 [references/exception-handler-details.md](references/exception-handler-details.md)\n\n## 整合測試基礎設施\n\n測試基礎設施由三個核心組件構成：\n\n- **TestWebApplicationFactory**：繼承 `WebApplicationFactory<Program>`，配置多容器（PostgreSQL + Redis）與 DI 替換（如 FakeTimeProvider）\n- **IntegrationTestCollection**：Collection Fixture 定義，確保容器共享\n- **IntegrationTestBase**：測試基底類別，提供 HttpClient、DatabaseManager、FlurlClient 與時間控制方法\n\n> 完整基礎設施程式碼請參閱 [references/test-infrastructure.md](references/test-infrastructure.md)\n\n## Flurl 簡化 URL 建構\n\n```csharp\n// 傳統方式\nvar url = $\"/products?pageSize={pageSize}&page={page}&keyword={keyword}\";\n\n// 使用 Flurl\nvar url = \"/products\"\n    .SetQueryParam(\"pageSize\", 5)\n    .SetQueryParam(\"page\", 2)\n    .SetQueryParam(\"keyword\", \"特殊\");\n```\n\n## 測試範例\n\n涵蓋成功建立產品（201 Created）、驗證錯誤（400 BadRequest + ValidationProblemDetails）、資源不存在（404 NotFound + ProblemDetails）、分頁查詢（200 OK + PagedResult）等完整測試範例，以及 TestHelpers 資料管理策略。\n\n> 完整測試範例與資料管理程式碼請參閱 [references/test-examples.md](references/test-examples.md)\n\n## 最佳實務\n\n### 1. 測試結構設計\n\n- **單一職責**：每個測試專注於一個特定場景\n- **3A 模式**：清楚區分 Arrange、Act、Assert\n- **清晰命名**：方法名稱表達測試意圖\n\n### 2. 錯誤處理驗證\n\n- **ValidationProblemDetails**：驗證錯誤回應格式\n- **ProblemDetails**：驗證業務異常回應\n- **HTTP 狀態碼**：確認正確的狀態碼\n\n### 3. 效能考量\n\n- **容器共享**：使用 Collection Fixture\n- **資料清理**：測試後清理資料，不重建容器\n- **並行執行**：確保測試獨立性\n\n## 相依套件\n\n```xml\n<PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n<PackageReference Include=\"AwesomeAssertions\" Version=\"9.4.0\" />\n<PackageReference Include=\"Testcontainers.PostgreSql\" Version=\"4.11.0\" />\n<PackageReference Include=\"Testcontainers.Redis\" Version=\"4.11.0\" />\n<PackageReference Include=\"Microsoft.AspNetCore.Mvc.Testing\" Version=\"9.0.0\" />\n<PackageReference Include=\"Flurl\" Version=\"4.0.0\" />\n<PackageReference Include=\"Respawn\" Version=\"7.0.0\" />\n```\n\n## 專案結構\n\n```text\nsrc/\n├── Api/                          # WebApi 層\n├── Application/                  # 應用服務層\n├── Domain/                       # 領域模型\n└── Infrastructure/               # 基礎設施層\ntests/\n└── Integration/\n    ├── Fixtures/\n    │   ├── TestWebApplicationFactory.cs\n    │   ├── IntegrationTestCollection.cs\n    │   └── IntegrationTestBase.cs\n    ├── Handlers/\n    │   ├── GlobalExceptionHandler.cs\n    │   └── FluentValidationExceptionHandler.cs\n    ├── Helpers/\n    │   ├── DatabaseManager.cs\n    │   └── TestHelpers.cs\n    ├── SqlScripts/\n    │   └── Tables/\n    └── Controllers/\n        └── ProductsControllerTests.cs\n```\n\n## 輸出格式\n\n- 產生 `TestWebApplicationFactory.cs`，配置多容器（PostgreSQL + Redis）與 DI 替換\n- 產生 `IntegrationTestCollection.cs` 與 `IntegrationTestBase.cs` 測試基礎設施\n- 產生 `DatabaseManager.cs`，整合 Respawn 進行測試資料清理\n- 產生控制器測試類別，驗證 CRUD、ProblemDetails 與 ValidationProblemDetails\n- 產生 `GlobalExceptionHandler.cs` 與 `FluentValidationExceptionHandler.cs` 異常處理器\n\n## 參考資源\n\n### 原始文章\n\n本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章：\n\n- **Day 23 - 整合測試實戰：WebApi 服務的整合測試**\n  - 鐵人賽文章：https://ithelp.ithome.com.tw/articles/10376873\n  - 範例程式碼：https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day23\n\n### 官方文件\n\n- [ASP.NET Core 整合測試](https://docs.microsoft.com/aspnet/core/test/integration-tests)\n- [IExceptionHandler 文件](https://learn.microsoft.com/aspnet/core/fundamentals/error-handling)\n- [ProblemDetails RFC 7807](https://tools.ietf.org/html/rfc7807)\n- [Testcontainers for .NET](https://dotnet.testcontainers.org/)\n- [AwesomeAssertions](https://awesomeassertions.org/)\n- [Flurl HTTP Client](https://flurl.dev/)\n- [Respawn](https://github.com/jbogard/Respawn)\n\n### 相關技能\n\n- `dotnet-testing-advanced-aspnet-integration-testing` - ASP.NET Core 基礎整合測試\n- `dotnet-testing-advanced-testcontainers-database` - 資料庫容器測試\n- `dotnet-testing-advanced-testcontainers-nosql` - NoSQL 容器測試\n- `dotnet-testing-fluentvalidation-testing` - FluentValidation 測試","tags":["dotnet","testing","advanced","webapi","integration","agent","skills","kevintsengtw","agent-skills","ai-assisted-development","copilot-skills","csharp"],"capabilities":["skill","source-kevintsengtw","skill-dotnet-testing-advanced-webapi-integration-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-webapi-integration-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 (4,769 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.699Z","embedding":null,"createdAt":"2026-04-18T23:04:20.234Z","updatedAt":"2026-04-24T13:02:25.699Z","lastSeenAt":"2026-04-24T13:02:25.699Z","tsv":"'/)':365,369,375 '/articles/10376873':337 '/aspnet/core/fundamentals/error-handling)':353 '/aspnet/core/test/integration-tests)':348 '/html/rfc7807)':359 '/jbogard/respawn)':379 '/kevintsengtw/30days_in_testing_samples/tree/main/day23':341 '/products':185,196 '1':47,230 '2':51,202,242 '200':219 '201':208 '23':330 '3':55,251 '30':326 '3a':234 '4':61 '400':96,211 '404':94,215 '5':69,199 '500':98 '6':75 '7807':105,356 '8':85 'act':238 'advanc':4,384,394,401 'api':267 'applic':270 'argumentexcept':95 'arrang':237 'asp.net':8,83,343,388 'aspnet':385 'assert':239 'awesomeassert':25,71,366 'awesomeassertions.org':368 'awesomeassertions.org/)':367 'badrequest':212 'client':372 'collect':163,255 'control':290 'core':9,84,344,389 'creat':209 'crud':313 'csharp':181 'databas':396 'databasemanag':171 'databasemanager.cs':286,307 'day':329 'detail':117 'di':158,299 'docs.microsoft.com':347 'docs.microsoft.com/aspnet/core/test/integration-tests)':346 'domain':272 'dotnet':2,382,392,399,407 'dotnet-testing-advanced-aspnet-integration-test':381 'dotnet-testing-advanced-testcontainers-databas':391 'dotnet-testing-advanced-testcontainers-nosql':398 'dotnet-testing-advanced-webapi-integration-test':1 'dotnet-testing-fluentvalidation-test':406 'dotnet.testcontainers.org':364 'dotnet.testcontainers.org/)':363 'error':127 'faketimeprovid':161 'fixtur':164,256,278 'fluentvalid':130,132,144,409,411 'fluentvalidationexceptionhandler.cs':284,320 'flurl':22,63,177,193,370 'flurl.dev':374 'flurl.dev/)':373 'flurlclient':172 'github.com':340,378 'github.com/jbogard/respawn)':377 'github.com/kevintsengtw/30days_in_testing_samples/tree/main/day23':339 'globalexceptionhandl':91 'globalexceptionhandler.cs':283,318 'handler':282 'helper':285 'http':26,65,73,115,248,371 'httpclient':170 'iexceptionhandl':19,53,81,87,134,349 'infrastructur':274 'instanc':119 'integr':6,39,277,386 'integrationtestbas':167 'integrationtestbase.cs':281,304 'integrationtestcollect':162 'integrationtestcollection.cs':280,302 'ithelp.ithome.com.tw':336 'ithelp.ithome.com.tw/articles/10376873':335 'keynotfoundexcept':93 'keyword':190,191,204 'learn.microsoft.com':352 'learn.microsoft.com/aspnet/core/fundamentals/error-handling)':351 'make':28 'mention':37 'middlewar':89 'net':362 'nosql':403,404 'notfound':216 'ok':220 'page':188,189,201 'pagedresult':221 'pages':186,187,198 'postgresql':77,155,296 'problemdetail':15,41,57,100,102,125,217,246,314,354 'productscontrollertests.cs':291 'redi':78,156,297 'references/exception-handler-details.md':147,148 'references/test-examples.md':227,228 'references/test-infrastructure.md':175,176 'respawn':309,376 'rfc':104,355 'setqueryparam':197,200,203 'skill':33 'skill-dotnet-testing-advanced-webapi-integration-testing' 'source-kevintsengtw' 'sqlscript':288 'src':266 'status':114 'sure':29 'tabl':289 'test':3,7,40,276,383,387,393,400,408,410 'testcontain':20,360,395,402 'testhelp':224 'testhelpers.cs':287 'testwebapplicationfactori':151 'testwebapplicationfactory.cs':279,294 'text':265 'titl':112 'tools.ietf.org':358 'tools.ietf.org/html/rfc7807)':357 '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' 'type':109 'uri':111,121 'url':23,67,179,184,195 'use':31 'user':36 'validationexcept':137 'validationproblemdetail':59,122,139,213,244,316 'var':183,194 'webapi':5,10,13,38,42,49,268,332 'webapplicationfactori':18,153 'whenev':34 'xml':263 '不重建容器':259 '並行執行':260 '介面':135 '介面提供了比傳統':88 '以及':223 '使用':52,62,70,192,254 '依據例外類型':92 '傳統方式':182 '其他':97 '分頁查詢':218 '原始文章':323 '參考資源':322 '和':58 '問題類型的':110 '單一職責':232 '回應':101 '回應驗證':74 '基礎整合測試':390 '基礎設施層':275 '多容器編排':21 '天挑戰':327 '如':143,160 '字典':128 '學習目標':44 '完成本技能學習後':45 '完整基礎設施程式碼請參閱':174 '完整實作程式碼請參閱':146 '完整測試範例與資料管理程式碼請參閱':226 '官方文件':342 '定義':165 '定義的統一錯誤回應格式':106 '容器共享':253 '容器測試':405 '實作現代化異常處理':54 '將驗證錯誤轉換為標準的':138 '專案結構':264 '專門處理':136 '層':269 '建構':68,180 '建構與':24 '建立多容器':76 '建立完整的':48 '引入的':86 '必須在全域處理器之前註冊':145 '您將能夠':46 '應用服務層':271 '提供':169 '效能考量':252 '整合':308 '整合測試':43,345 '整合測試基礎設施':149 '整合測試完整指南':11 '整合測試實戰':331 '整合測試架構':50 '文件':350 '方法名稱表達測試意圖':241 '更優雅的錯誤處理方式':90 '替換':159,300 '最佳實務':229 '服務的整合測試':333 '本技能內容提煉自':324 '核心概念':80 '格式回應':140 '標準格式':60,103 '模式':235 '欄位':107 '每個測試專注於一個特定場景':233 '涵蓋':17 '涵蓋成功建立產品':207 '清晰命名':240 '清楚區分':236 '測試':412 '測試基底類別':168 '測試基礎設施':305 '測試基礎設施由三個核心組件構成':150 '測試後清理資料':258 '測試環境':79 '測試的':66 '測試範例':206 '測試結構設計':231 '特定處理器':142 '特殊':205 '狀態碼':116,249 '現代化異常處理':82 '產生':293,301,306,317 '產生對應的':99 '產生控制器測試類別':311 '異常處理器':131,321 '異常處理器實作':133 '當需要對':12 '發生問題的實例':120 '相依套件':262 '相關技能':380 '確保容器共享':166 '確保測試獨立性':261 '確認正確的狀態碼':250 '端點進行整合測試或驗證':14 '等完整測試範例':222 '範例程式碼':338 '簡化':64,178 '簡短的錯誤描述':113 '系列文章':328 '繼承':152 '繼承自':124 '老派軟體工程師的測試修練':325 '與':157,298,303,315,319 '與時間控制方法':173 '處理器之間按照註冊順序執行':141 '記錄每個欄位的驗證錯誤訊息':129 '詳細的錯誤說明':118 '說明':108 '資料庫容器測試':397 '資料清理':257 '資料管理策略':225 '資源不存在':214 '輸出格式':292 '進行測試資料清理':310 '進行精確的':72 '配置多容器':154,295 '錯誤格式時使用':16 '錯誤處理驗證':243 '鐵人賽文章':334 '領域模型':273 '額外包含':126 '驗證':27,56,312 '驗證業務異常回應':247 '驗證錯誤':210 '驗證錯誤回應格式':245 '驗證錯誤專用':123","prices":[{"id":"ec3c1113-3aff-4540-a4c3-a85e410832d7","listingId":"149fb0b7-705c-431a-8dfa-95e95a663b6d","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:20.234Z"}],"sources":[{"listingId":"149fb0b7-705c-431a-8dfa-95e95a663b6d","source":"github","sourceId":"kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-advanced-webapi-integration-testing","sourceUrl":"https://github.com/kevintsengtw/dotnet-testing-agent-skills/tree/main/skills/dotnet-testing-advanced-webapi-integration-testing","isPrimary":false,"firstSeenAt":"2026-04-18T23:04:20.234Z","lastSeenAt":"2026-04-24T13:02:25.699Z"}],"details":{"listingId":"149fb0b7-705c-431a-8dfa-95e95a663b6d","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"kevintsengtw","slug":"dotnet-testing-advanced-webapi-integration-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":"c0b6988ef0c14f1243d51cdf5951359603702a1a","skill_md_path":"skills/dotnet-testing-advanced-webapi-integration-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/kevintsengtw/dotnet-testing-agent-skills/tree/main/skills/dotnet-testing-advanced-webapi-integration-testing"},"layout":"multi","source":"github","category":"dotnet-testing-agent-skills","frontmatter":{"name":"dotnet-testing-advanced-webapi-integration-testing","description":"ASP.NET Core WebApi 整合測試完整指南。當需要對 WebApi 端點進行整合測試或驗證 ProblemDetails 錯誤格式時使用。涵蓋 WebApplicationFactory、IExceptionHandler、Testcontainers 多容器編排、Flurl URL 建構與 AwesomeAssertions HTTP 驗證。\nMake sure to use this skill whenever the user mentions WebApi integration testing, ProblemDetails, IExceptionHandler, Flurl, Respawn, or multi-container test orchestration, even if they don't explicitly ask for WebApi testing guidance.\nKeywords: webapi integration testing, WebApplicationFactory, asp.net core integration test, webapi 整合測試, IExceptionHandler, ProblemDetails, ValidationProblemDetails, AwesomeAssertions, Flurl, Respawn, Be201Created, Be400BadRequest, 多容器測試, Collection Fixture, 全域例外處理"},"skills_sh_url":"https://skills.sh/kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-advanced-webapi-integration-testing"},"updatedAt":"2026-04-24T13:02:25.699Z"}}