$npx -y skills add kevintsengtw/dotnet-testing-agent-skills --skill dotnet-testing-autofixture-bogus-integrationAutoFixture 與 Bogus 整合完整指南。當需要結合 AutoFixture 與 Bogus 產生兼具匿名性與真實感的測試資料時使用。涵蓋 SpecimenBuilder 整合、混合產生器、測試資料工廠與循環參考處理。 Make sure to use this skill whenever the user mentions AutoFixture with Bogus, Faker integration, realistic test data, semantic test data, or HybridTestDataGenerato
| 1 | # AutoFixture 與 Bogus 整合應用指南 |
| 2 | |
| 3 | ## 核心概念 |
| 4 | |
| 5 | ### 為什麼需要整合? |
| 6 | |
| 7 | | 面向 | AutoFixture | Bogus | 整合方案 | |
| 8 | | -------------- | ------------------------ | ------------------------ | ---------------- | |
| 9 | | 資料真實感 | 低(GUID 格式字串) | 高(真實 Email/Phone) | 高 | |
| 10 | | 物件關聯處理 | 自動 | 手動 | 自動 | |
| 11 | | 循環參考處理 | 內建 | 無 | 整合 | |
| 12 | | 設定複雜度 | 低 | 中 | 中 | |
| 13 | | 適用場景 | 單元測試 | 整合測試/原型 | 兩者皆可 | |
| 14 | |
| 15 | **整合效果:** `user.Email` 從 `"Email1a2b3c4d"` 變為 `"john.doe@example.com"`,其他屬性仍由 AutoFixture 自動填充。 |
| 16 | |
| 17 | ## 套件安裝 |
| 18 | |
| 19 | ```xml |
| 20 | <PackageReference Include="AutoFixture" Version="4.18.1" /> |
| 21 | <PackageReference Include="AutoFixture.Xunit2" Version="4.18.1" /> |
| 22 | <PackageReference Include="Bogus" Version="35.6.5" /> |
| 23 | <PackageReference Include="xunit" Version="2.9.3" /> |
| 24 | <PackageReference Include="AwesomeAssertions" Version="9.4.0" /> |
| 25 | ``` |
| 26 | |
| 27 | ## 整合方式總覽 |
| 28 | |
| 29 | | 整合方式 | 適用場景 | 複雜度 | |
| 30 | | ---------------------------- | ------------------ | ------ | |
| 31 | | 屬性層級 SpecimenBuilder | 特定屬性使用 Bogus | 低 | |
| 32 | | 類型層級 SpecimenBuilder | 整個類型使用 Bogus | 中 | |
| 33 | | 混合產生器 (HybridGenerator) | 統一 API 整合 | 中 | |
| 34 | | 整合工廠 (IntegratedFactory) | 完整測試場景建構 | 高 | |
| 35 | | 自訂 AutoData 屬性 | xUnit 整合 | 低 | |
| 36 | |
| 37 | ## 核心整合技術 |
| 38 | |
| 39 | ### ISpecimenBuilder 整合 |
| 40 | |
| 41 | 透過 `ISpecimenBuilder` 介面實現屬性層級與類型層級的整合: |
| 42 | |
| 43 | - **屬性層級**:根據屬性名稱判斷(如 `Email`、`Phone`、`FirstName`),使用 Bogus 產生對應的真實感資料 |
| 44 | - **類型層級**:為整個類型(如 `User`、`Address`)註冊 Bogus Faker 產生器 |
| 45 | |
| 46 | ### 常用 SpecimenBuilder |
| 47 | |
| 48 | | SpecimenBuilder | 產生資料類型 | Bogus API | |
| 49 | | ------------------------ | ------------------ | ------------------------ | |
| 50 | | `EmailSpecimenBuilder` | Email 地址 | `f.Internet.Email()` | |
| 51 | | `PhoneSpecimenBuilder` | 電話號碼 | `f.Phone.PhoneNumber()` | |
| 52 | | `NameSpecimenBuilder` | 人名 | `f.Name.FirstName()` | |
| 53 | | `AddressSpecimenBuilder` | 地址 | `f.Address.FullAddress()`| |
| 54 | |
| 55 | ### 擴充方法 |
| 56 | |
| 57 | - `fixture.WithBogus()` — 註冊所有 Bogus SpecimenBuilder |
| 58 | - `fixture.WithOmitOnRecursion()` — 處理循環參考 |
| 59 | - `fixture.WithSeed(seed)` — 設定隨機種子 |
| 60 | - `fixture.WithRepeatCount(count)` — 設定 CreateMany 預設數量 |
| 61 | |
| 62 | > 完整內容請參閱 [references/core-integration-techniques.md](references/core-integration-techniques.md) |
| 63 | |
| 64 | ## 循環參考處理 |
| 65 | |
| 66 | 當物件存在循環參考(如 User → Company → Employees(User))時,使用 `OmitOnRecursionBehavior` 解決: |
| 67 | |
| 68 | ```csharp |
| 69 | var fixture = new Fixture(); |
| 70 | fixture.Behaviors.OfType<ThrowingRecursionBehavior>() |
| 71 | .ToList() |
| 72 | .ForEach(b => fixture.Behaviors.Remove(b)); |
| 73 | fixture.Behaviors.Add(new OmitOnRecursionBehavior()); |
| 74 | ``` |
| 75 | |
| 76 | **效果:** 避免 StackOverflowException,循環參考的屬性設為 null 或空集合。 |
| 77 | |
| 78 | ## 自訂 AutoData 屬性 |
| 79 | |
| 80 | ```csharp |
| 81 | public class BogusAutoDataAttribute : AutoDataAttribute |
| 82 | { |
| 83 | public BogusAutoDataAttribute() |
| 84 | : base(() => new Fixture().WithBogus()) |
| 85 | { |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // 使用方式 |
| 90 | [Theory] |
| 91 | [BogusAutoData] |
| 92 | public void 使用整合資料測試(User user, Address address) |
| 93 | { |
| 94 | user.Email.Should().Contain("@"); |
| 95 | address.City.Should().NotBeNullOrEmpty(); |
| 96 | } |
| 97 | ``` |
| 98 | |
| 99 | ## 混合產生器與測試資料工廠 |
| 100 | |
| 101 | ### HybridTestDataGenerator |
| 102 | |
| 103 | 統一的測試資料產生 API,實作 `ITestDataGenerator` 介面: |
| 104 | |
| 105 | - `Generate<T>()` — 產生單一物件 |
| 106 | - `Generate<T>(int count)` — 產生指定數量的集合 |
| 107 | - `Generate<T>(Action<T> configure)` — 產生物件後進行自訂設定 |
| 108 | |
| 109 | ### IntegratedTestDataFactory |
| 110 | |
| 111 | 完整場景建構工廠,支援進階功能: |
| 112 | |
| 113 | - `CreateFresh<T>()` — 每次產生全新物件 |
| 114 | - `CreateMany<T>(count)` — 批次建立 |
| 115 | - `GetCached<T>()` — 快取機制,相同類型只產生一次 |
| 116 | - `CreateTestScenario()` — 建立包含 Company、Users、Orders 的完整測試場景,自動建立關聯 |
| 117 | |
| 118 | ### TestBase 基底類別 |
| 119 | |
| 120 | 統一 Fixture、Generator、Factory 的初始化與 Seed 管理,提供 `Create<T>()`、`CreateMany<T>()`、`Create<T>(configure)` 等便捷方法。 |
| 121 | |
| 122 | > 完整程式碼範例請參考 [references/hybrid-generator-and-factory.md](references/hybrid-generator-and-factory.md) |
| 123 | |
| 124 | ## Seed 管理與可重現性 |
| 125 | |
| 126 | ### 重要限制 |
| 127 | |
| 128 | 由於 AutoFixture 和 Bogus 有不同的隨機數管理機制: |
| 129 | |
| 130 | - Seed 確保測試行為穩定性 |
| 131 | - Seed 確保資料格式一致性 |
| 132 | - 無法保證所有屬性值完全相同 |
| 133 | |
| 134 | ### 建議做法 |
| 135 | |
| 136 | - **一般場景**:使用 `IntegratedTestDataFactory(seed: 12345)` 確保穩定性 |
| 137 | - **完全可重現**:使用單一工具,如 `Faker<User>().UseSeed(12345)` |
| 138 | - **不需重現**:不設定 Seed,每次產生不同的隨機資料 |
| 139 | |
| 140 | ## 常見問題 |
| 141 | |
| 142 | ### Q1: 什麼時候該用整合方案,什麼時候用單一工具? |
| 143 | |
| 144 | - **用整合方案**:需要真實感資料(Email、Phone)且物件結構複雜的測試場景 |
| 145 | - **用純 AutoFixture**:只需要匿名資料填充的單元測試 |
| 146 | - **用純 Bogus**:需要完全可重現且資料格式嚴格的整合測試 |
| 147 | |
| 148 | ### Q2: SpecimenBuilder 匹配優先順序? |
| 149 | |
| 150 | AutoFixture 按照 `Customizations` 集合的順序匹配,先加入的 Builder 優先。使用 `fixture.Customizations.Insert(0, builder)` 可 |