用途
本技能針對 ASP.NET Core WebApi 提供整合測試的完整指引,主要用於對 WebApi 端點進行整合測試,以及驗證 ProblemDetails 錯誤回應格式。內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章,並整理成可套用的技能與範本。
主要能力
- 建立完整的 WebApi 整合測試架構。
- 使用 IExceptionHandler 實作現代化異常處理。
- 驗證 ProblemDetails 與 ValidationProblemDetails 標準格式。
- 使用 Flurl 簡化 HTTP 測試的 URL 建構。
- 使用 AwesomeAssertions 進行精確的 HTTP 回應驗證。
- 建立多容器(PostgreSQL + Redis)測試環境。
核心概念
IExceptionHandler 現代化異常處理
ASP.NET Core 8+ 引入的 IExceptionHandler 介面提供比傳統 middleware 更優雅的錯誤處理方式。GlobalExceptionHandler 會依例外類型產生對應的 ProblemDetails 回應,例如 KeyNotFoundException 對應 404、ArgumentException 對應 400、其他對應 500。
ProblemDetails 標準格式
RFC 7807 定義的統一錯誤回應格式包含以下欄位:
- type:問題類型的 URI
- title:簡短的錯誤描述
- status:HTTP 狀態碼
- detail:詳細的錯誤說明
- instance:發生問題的實例 URI
ValidationProblemDetails
繼承自 ProblemDetails,額外包含 errors 字典,記錄每個欄位的驗證錯誤訊息。
FluentValidation 異常處理器
FluentValidation 異常處理器實作 IExceptionHandler 介面,專門處理 ValidationException,將驗證錯誤轉換為標準的 ValidationProblemDetails 格式回應。處理器之間按照註冊順序執行,特定處理器(如 FluentValidation)必須在全域處理器之前註冊。完整實作程式碼請參閱 references/exception-handler-details.md。
整合測試基礎設施
測試基礎設施由三個核心組件構成:
- TestWebApplicationFactory:繼承 WebApplicationFactory<Program>,配置多容器(PostgreSQL + Redis)與 DI 替換(如 FakeTimeProvider)。FakeTimeProvider 由 Collection 內所有測試共用,只能往前推;不要在每個測試開始時設回固定起點,時間斷言改以 Factory.TimeProvider.GetUtcNow() 推算。
- IntegrationTestCollection:Collection Fixture 定義,確保容器共享。
- IntegrationTestBase:測試基底類別,提供 HttpClient、DatabaseManager、FlurlClient 與時間控制方法。
完整基礎設施程式碼請參閱 references/test-infrastructure.md。
使用方式
Flurl 簡化 URL 建構
傳統方式:
var url = $"/products?pageSize={pageSize}&page={page}&keyword={keyword}";
使用 Flurl:
var url = "/products"
.SetQueryParam("pageSize", 5)
.SetQueryParam("page", 2)
.SetQueryParam("keyword", "特殊");
測試範例
涵蓋成功建立產品(201 Created)、驗證錯誤(400 BadRequest + ValidationProblemDetails)、資源不存在(404 NotFound + ProblemDetails)、分頁查詢(200 OK + PagedResult)等完整測試範例,以及 TestHelpers 資料管理策略。完整測試範例與資料管理程式碼請參閱 references/test-examples.md。
最佳實務
測試結構設計
- 單一職責:每個測試專注於一個特定場景。
- 3A 模式:清楚區分 Arrange、Act、Assert。
- 清晰命名:方法名稱表達測試意圖。
錯誤處理驗證
- ValidationProblemDetails:驗證錯誤回應格式。
- ProblemDetails:驗證業務異常回應。
- HTTP 狀態碼:確認正確的狀態碼。
效能考量
- 容器共享:使用 Collection Fixture。
- 資料清理:測試後清理資料,不重建容器。
- 並行執行:確保測試獨立性。
相依套件
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.11.0" />
<PackageReference Include="Testcontainers.Redis" Version="4.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
<PackageReference Include="Flurl" Version="4.0.0" />
<PackageReference Include="Respawn" Version="7.0.0" />
專案結構
src/
├── Api/ # WebApi 層
├── Application/ # 應用服務層
├── Domain/ # 領域模型
└── Infrastructure/ # 基礎設施層
tests/
└── Integration/
├── Fixtures/
│ ├── TestWebApplicationFactory.cs
│ ├── IntegrationTestCollection.cs
│ └── IntegrationTestBase.cs
├── Handlers/
│ ├── GlobalExceptionHandler.cs
│ └── FluentValidationExceptionHandler.cs
├── Helpers/
│ ├── DatabaseManager.cs
│ └── TestHelpers.cs
├── SqlScripts/
│ └── Tables/
└── Controllers/
└── ProductsControllerTests.cs
輸出格式
- 產生 TestWebApplicationFactory.cs,配置多容器(PostgreSQL + Redis)與 DI 替換。
- 產生 IntegrationTestCollection.cs 與 IntegrationTestBase.cs 測試基礎設施。
- 產生 DatabaseManager.cs,整合 Respawn 進行測試資料清理。
- 產生控制器測試類別,驗證 CRUD、ProblemDetails 與 ValidationProblemDetails。
- 產生 GlobalExceptionHandler.cs 與 FluentValidationExceptionHandler.cs 異常處理器。
參考資源
範例檔案
- templates/test-web-application-factory.cs:TestWebApplicationFactory,以 IAsyncLifetime 管理容器生命週期。
- templates/integration-test-base.cs:IntegrationTestBase 基底類別與 IntegrationTestCollection 共用容器設定。
- templates/database-manager.cs:DatabaseManager,負責測試資料庫的初始化與重置。
- templates/create-products-table.sql:products 資料表的 DDL,示範 SQL 腳本外部化。
- templates/products-controller-tests.cs:Controller 的完整 CRUD 測試,含請求與回應模型。
- templates/global-exception-handler.cs:實作 IExceptionHandler 的全域例外處理器。
- templates/fluent-validation-exception-handler.cs:FluentValidation 例外處理器,回傳 ValidationProblemDetails。註冊順序需先於全域處理器。
- templates/test-project.csproj:測試專案設定(net9.0、xUnit 2.9.3、AwesomeAssertions 9.4.0)。
原始文章
本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
- Day 23 - 整合測試實戰:WebApi 服務的整合測試
- 鐵人賽文章:https://ithelp.ithome.com.tw/articles/10376873
- 範例程式碼:https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day23
官方文件
- ASP.NET Core 整合測試
- IExceptionHandler 文件
- ProblemDetails RFC 7807
- Testcontainers for .NET
- AwesomeAssertions
- Flurl HTTP Client
- Respawn
相關技能
- dotnet-testing-advanced-aspnet-integration-testing:ASP.NET Core 基礎整合測試
- dotnet-testing-advanced-testcontainers-database:資料庫容器測試
- dotnet-testing-advanced-testcontainers-nosql:NoSQL 容器測試
- dotnet-testing-fluentvalidation-testing:FluentValidation 測試
限制
本技能聚焦於 ASP.NET Core WebApi 整合測試與 ProblemDetails 驗證,未涵蓋其他測試類型或非 .NET 平台的整合測試。實際收費、平台支援範圍與執行環境需求暫未提供。