# 測試架構說明 ## 概述 本測試架構採用三層測試策略:單元測試、整合測試、端到端測試。支援 xUnit 測試框架,並整合 Moq 進行 Mock 測試。 ## 測試目錄結構 ``` Tests/ ├── README.md # 本文檔 - 測試架構說明 ├── Unit/ # 單元測試 │ ├── Services/ # 服務層單元測試 │ ├── Controllers/ # 控制器單元測試 │ └── Repositories/ # Repository 單元測試 ├── Integration/ # 整合測試 └── E2E/ # 端到端測試 ``` ## 測試框架與工具 ### 核心測試框架 - **xUnit**: 主要測試框架 - **Moq**: Mock 物件框架 - **FluentAssertions**: 流暢斷言庫 - **Microsoft.AspNetCore.Mvc.Testing**: ASP.NET Core 測試支援 ### 測試資料庫 - **SQLite In-Memory**: 用於快速單元測試 - **TestContainers**: 用於整合測試的容器化資料庫 ## 單元測試規範 ### 命名規範 ``` {TestedMethod}_{Scenario}_{ExpectedResult} 例如: - GetUserAsync_WithValidId_ReturnsUser() - AnalyzeSentenceAsync_WithEmptyText_ThrowsArgumentException() ``` ### 測試結構 (Arrange-Act-Assert) ```csharp [Fact] public async Task GetUserAsync_WithValidId_ReturnsUser() { // Arrange var userId = 1; var expectedUser = new User { Id = userId, Name = "Test User" }; var mockRepository = new Mock(); mockRepository.Setup(r => r.GetByIdAsync(userId)) .ReturnsAsync(expectedUser); var service = new UserService(mockRepository.Object); // Act var result = await service.GetUserAsync(userId); // Assert result.Should().NotBeNull(); result.Id.Should().Be(userId); result.Name.Should().Be("Test User"); } ``` ## 服務層測試指南 ### 測試重點服務 1. **GeminiService** - AI 服務核心功能 2. **AuthService** - 認證服務 3. **AnalysisService** - 分析服務 4. **RefactoredHybridCacheService** - 快取服務 ### Mock 策略 - **外部 API 呼叫**: 使用 Mock HttpClient - **資料庫操作**: Mock Repository 介面 - **檔案操作**: Mock 檔案系統相關服務 ## 整合測試策略 ### WebApplicationFactory 使用 ASP.NET Core 的 `WebApplicationFactory` 進行整合測試: ```csharp public class IntegrationTestBase : IClassFixture> { protected readonly WebApplicationFactory Factory; protected readonly HttpClient Client; public IntegrationTestBase(WebApplicationFactory factory) { Factory = factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Testing"); builder.ConfigureServices(services => { // 替換為測試資料庫 services.RemoveAll>(); services.AddDbContext(options => options.UseInMemoryDatabase("TestDb")); }); }); Client = Factory.CreateClient(); } } ``` ### 測試資料管理 ```csharp public class TestDataSeeder { public static async Task SeedAsync(DramaLingDbContext context) { // 清理現有資料 context.Users.RemoveRange(context.Users); // 新增測試資料 context.Users.Add(new User { Id = 1, Name = "Test User" }); await context.SaveChangesAsync(); } } ``` ## 測試執行命令 ### 執行所有測試 ```bash dotnet test ``` ### 執行特定類別的測試 ```bash dotnet test --filter "ClassName=GeminiServiceTests" ``` ### 執行特定類型的測試 ```bash # 只執行單元測試 dotnet test --filter "Category=Unit" # 只執行整合測試 dotnet test --filter "Category=Integration" ``` ### 產生測試覆蓋率報告 ```bash dotnet test --collect:"XPlat Code Coverage" ``` ## 測試資料工廠模式 ### 實體建立工廠 ```csharp public static class TestDataFactory { public static User CreateUser(int id = 1, string name = "Test User") { return new User { Id = id, Name = name, Email = $"test{id}@example.com", CreatedAt = DateTime.UtcNow }; } public static Flashcard CreateFlashcard(int id = 1, int userId = 1) { return new Flashcard { Id = id, UserId = userId, Front = "Test Front", Back = "Test Back", CreatedAt = DateTime.UtcNow }; } } ``` ## CI/CD 整合 ### GitHub Actions 設定範例 ```yaml name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET uses: actions/setup-dotnet@v1 with: dotnet-version: '8.0.x' - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --no-restore - name: Test run: dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage" - name: Upload coverage reports uses: codecov/codecov-action@v1 ``` ## 效能測試指南 ### 基準測試 使用 BenchmarkDotNet 進行效能測試: ```csharp [MemoryDiagnoser] [SimpleJob(RuntimeMoniker.Net80)] public class CachingBenchmarks { private ICacheService _cacheService; [GlobalSetup] public void Setup() { // 初始化快取服務 } [Benchmark] public async Task GetFromCache() { return await _cacheService.GetAsync("test-key"); } } ``` ## 測試最佳實踐 ### DRY 原則 - 建立共用的測試基類 - 使用測試資料工廠 - 抽取共同的 Setup 邏輯 ### 測試隔離 - 每個測試應該獨立執行 - 避免測試之間的依賴關係 - 使用 `IDisposable` 清理資源 ### 可讀性 - 使用描述性的測試名稱 - 明確的 Arrange-Act-Assert 結構 - 適量的註解說明複雜邏輯 ## 未來擴展計劃 1. **測試覆蓋率目標**: 達到 80% 以上的程式碼覆蓋率 2. **自動化測試**: 整合 CI/CD 管道 3. **效能回歸測試**: 建立效能基準測試 4. **安全性測試**: 加入安全相關的測試案例 --- **版本**: 1.0 **建立日期**: 2025-09-30 **維護者**: DramaLing 開發團隊