{"id":"720fbfca-d040-4cbb-8826-71da1b136f16","shortId":"hBuVkh","kind":"skill","title":"dotnet-testing-autofixture-customization","tagline":"AutoFixture 進階自訂化技術完整指南。當需要自訂 AutoFixture 建構器或處理特殊型別的測試資料產生規則時使用。涵蓋 DataAnnotations 自動整合、ISpecimenBuilder 實作、優先順序管理。包含 DateTime/數值範圍建構器、泛型化設計與流暢式擴充方法。\nMake sure to use this skill whenever the user mentions AutoFixture customization, ISpecimenBuilder, DataAnnotations with AutoFixt","description":"# AutoFixture 進階：自訂化測試資料生成策略\n\n## 概述\n\n本技能涵蓋 AutoFixture 的進階自訂化功能，讓您能根據業務需求精確控制測試資料的生成邏輯。\n\n### 核心技術\n\n1. **DataAnnotations 整合**：AutoFixture 自動識別 `[StringLength]`、`[Range]` 等驗證屬性\n2. **屬性範圍控制**：使用 `.With()` 配合 `Random.Shared` 動態產生隨機值\n3. **自訂 ISpecimenBuilder**：實作精確控制特定屬性的建構器\n4. **優先順序管理**：理解 `Insert(0)` vs `Add()` 的差異\n5. **泛型化設計**：建立支援多種數值型別的可重用建構器\n\n## 安裝套件\n\n```xml\n<PackageReference Include=\"AutoFixture\" Version=\"4.18.1\" />\n<PackageReference Include=\"AutoFixture.Xunit2\" Version=\"4.18.1\" />\n```\n\n## DataAnnotations 自動整合\n\nAutoFixture 能自動識別 `System.ComponentModel.DataAnnotations` 的驗證屬性：\n\n```csharp\npublic class Person\n{\n    public Guid Id { get; set; }\n    [StringLength(10)]\n    public string Name { get; set; } = string.Empty;\n    [Range(10, 80)]\n    public int Age { get; set; }\n    public DateTime CreateTime { get; set; }\n}\n\n[Fact]\npublic void AutoFixture_應能識別DataAnnotations()\n{\n    var fixture = new Fixture();\n    var person = fixture.Create<Person>();\n    person.Name.Length.Should().Be(10);        // StringLength(10)\n    person.Age.Should().BeInRange(10, 80);     // Range(10, 80)\n}\n```\n\n## 使用 .With() 控制屬性範圍\n\n### 固定值 vs 動態值\n\n```csharp\n// ❌ 固定值：只執行一次，所有物件相同值\n.With(x => x.Age, Random.Shared.Next(30, 50))\n\n// ✅ 動態值：每個物件都重新計算\n.With(x => x.Age, () => Random.Shared.Next(30, 50))\n```\n\n### Random.Shared 的優點\n\n| 特性       | `new Random()`             | `Random.Shared`      |\n| ---------- | -------------------------- | -------------------- |\n| 實例化方式 | 每次建立新實例             | 全域共用單一實例     |\n| 執行緒安全 | 不是                    | 是                |\n| 效能       | 多次建立有負擔，可能重複值 | 效能更佳，避免重複值 |\n\n## 自訂 ISpecimenBuilder\n\n涵蓋 RandomRangedDateTimeBuilder（精確控制特定 DateTime 屬性）、ImprovedRandomRangedNumericSequenceBuilder（改進版數值範圍建構器）、泛型化 NumericRangeBuilder&lt;TValue&gt;（支援 int/long/decimal/double/float 等多種型別），以及流暢介面擴充方法 AddRandomRange。每個建構器皆附完整實作與使用範例。\n\n> 完整 ISpecimenBuilder 實作範例請參考 [references/specimen-builder-examples.md](references/specimen-builder-examples.md)\n\n## 優先順序管理：Insert(0) vs Add()\n\nAutoFixture 內建的 `RangeAttributeRelay`、`NumericSequenceGenerator` 可能比自訂建構器有更高優先順序：\n\n```csharp\n// ❌ 可能失效：被內建建構器攔截\nfixture.Customizations.Add(new MyNumericBuilder(30, 50, \"Age\"));\n\n// ✅ 正確：確保最高優先順序\nfixture.Customizations.Insert(0, new MyNumericBuilder(30, 50, \"Age\"));\n```\n\n### int vs DateTime 處理差異\n\n| 型別       | 內建建構器                                        | 優先順序影響               |\n| ---------- | ------------------------------------------------- | -------------------------- |\n| `int`      | `RangeAttributeRelay`、`NumericSequenceGenerator` | 會被攔截，需用 `Insert(0)` |\n| `DateTime` | 無特定建構器                                      | 不會被攔截，`Add()` 即可   |\n\n## 最佳實踐\n\n### 應該做\n\n1. **善用 DataAnnotations** — 充分利用現有模型驗證規則，AutoFixture 自動產生符合限制的資料\n2. **使用 Random.Shared** — 避免重複值問題，執行緒安全、效能更好\n3. **Insert(0) 確保優先順序** — 自訂數值建構器務必用 `Insert(0)`\n4. **泛型化設計** — 建立可重用的泛型建構器，使用擴充方法提供流暢介面\n\n### 應該避免\n\n1. **忽略建構器優先順序** — 不要假設 `Add()` 一定生效\n2. **過度複雜的邏輯** — 建構器保持單一職責\n3. **使用 new Random()** — 可能產生重複值，非執行緒安全\n\n## 程式碼範本\n\n請參考 [templates](./templates) 資料夾中的範例檔案：\n\n- [dataannotations-integration.cs](./templates/dataannotations-integration.cs) - DataAnnotations 自動整合\n- [custom-specimen-builders.cs](./templates/custom-specimen-builders.cs) - 自訂 ISpecimenBuilder 實作\n- [numeric-range-extensions.cs](./templates/numeric-range-extensions.cs) - 泛型化數值範圍建構器與擴充方法\n\n## 與其他技能的關係\n\n- **autofixture-basics**：本技能的前置知識，需先掌握基礎用法\n- **autodata-xunit-integration**：下一步學習目標，將自訂化與 xUnit 整合\n- **autofixture-nsubstitute-integration**：進階整合，結合 Mock 與自訂資料生成\n\n## 輸出格式\n\n- 產生自訂 ISpecimenBuilder 實作類別\n- 產生 ICustomization 組合類別\n- 提供 fixture.Customizations.Insert(0, ...) 設定範例\n- 包含 DataAnnotations 整合與泛型化建構器程式碼\n\n## 參考資源\n\n### 原始文章\n\n本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章：\n\n- **Day 11 - AutoFixture 進階：自訂化測試資料生成策略**\n  - 鐵人賽文章：https://ithelp.ithome.com.tw/articles/10375153\n  - 範例程式碼：https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day11\n\n### 官方文件\n\n- [AutoFixture GitHub](https://github.com/AutoFixture/AutoFixture)\n- [AutoFixture 官方文件](https://autofixture.github.io/)\n- [ISpecimenBuilder 介面](https://autofixture.github.io/docs/fixture-customization/)","tags":["dotnet","testing","autofixture","customization","agent","skills","kevintsengtw","agent-skills","ai-assisted-development","copilot-skills","csharp","dotnet-testing"],"capabilities":["skill","source-kevintsengtw","skill-dotnet-testing-autofixture-customization","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-autofixture-customization","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,084 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:26.294Z","embedding":null,"createdAt":"2026-04-18T23:04:24.848Z","updatedAt":"2026-04-24T13:02:26.294Z","lastSeenAt":"2026-04-24T13:02:26.294Z","tsv":"'/)':372 '/articles/10375153':357 '/autofixture/autofixture)':367 '/docs/fixture-customization/)':377 '/kevintsengtw/30days_in_testing_samples/tree/main/day11':361 '/templates':292 '/templates/custom-specimen-builders.cs':299 '/templates/dataannotations-integration.cs':295 '/templates/numeric-range-extensions.cs':304 '0':69,204,224,243,265,269,337 '1':46,251,275 '10':94,102,128,130,133,136 '11':350 '2':54,257,280 '3':61,263,283 '30':152,160,218,227,346 '4':65,270 '5':73 '50':153,161,219,228 '80':103,134,137 'add':71,206,247,278 'addrandomrang':195 'age':106,220,229 'autodata':313 'autodata-xunit-integr':312 'autofixt':36 'autofixtur':4,6,9,31,37,42,49,80,117,207,255,308,321,351,363,368 'autofixture-bas':307 'autofixture-nsubstitute-integr':320 'autofixture.github.io':371,376 'autofixture.github.io/)':370 'autofixture.github.io/docs/fixture-customization/)':375 'basic':309 'beinrang':132 'class':86 'createtim':111 'csharp':84,144,212 'custom':5,32 'custom-specimen-builders.cs':298 'dataannot':12,34,47,78,253,296,340 'dataannotations-integration.cs':294 'datetim':18,110,184,232,244 'day':349 'dotnet':2 'dotnet-testing-autofixture-custom':1 'fact':114 'fixtur':120,122 'fixture.create':125 'fixture.customizations.add':215 'fixture.customizations.insert':223,336 'get':91,98,107,112 'github':364 'github.com':360,366 'github.com/autofixture/autofixture)':365 'github.com/kevintsengtw/30days_in_testing_samples/tree/main/day11':359 'guid':89 'icustom':333 'id':90 'improvedrandomrangednumericsequencebuild':186 'insert':68,203,242,264,268 'int':105,230,237 'int/long/decimal/double/float':192 'integr':315,323 'ispecimenbuild':14,33,63,180,198,301,330,373 'ithelp.ithome.com.tw':356 'ithelp.ithome.com.tw/articles/10375153':355 'make':21 'mention':30 'mock':326 'mynumericbuild':217,226 'name':97 'new':121,165,216,225,285 'nsubstitut':322 'numeric-range-extensions.cs':303 'numericrangebuild':189 'numericsequencegener':210,239 'person':87,124 'person.age.should':131 'person.name.length.should':126 'public':85,88,95,104,109,115 'random':166,286 'random.shared':59,162,167,259 'random.shared.next':151,159 'randomrangeddatetimebuild':182 'rang':52,101,135 'rangeattributerelay':209,238 'references/specimen-builder-examples.md':200,201 'set':92,99,108,113 'skill':26 'skill-dotnet-testing-autofixture-customization' 'source-kevintsengtw' 'string':96 'string.empty':100 'stringlength':51,93,129 'sure':22 'system.componentmodel.dataannotations':82 'templat':291 'test':3 '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' 'tvalu':190 'use':24 'user':29 'var':119,123 'void':116 'vs':70,142,205,231 'whenev':27 'x':149,157 'x.age':150,158 'xml':77 'xunit':314,318 '一定生效':279 '下一步學習目標':316 '不是':172 '不會被攔截':246 '不要假設':277 '介面':374 '以及流暢介面擴充方法':194 '使用':56,138,258,284 '使用擴充方法提供流暢介面':273 '優先順序影響':236 '優先順序管理':16,66,202 '充分利用現有模型驗證規則':254 '內建建構器':235 '內建的':208 '全域共用單一實例':170 '動態值':143,154 '動態產生隨機值':60 '包含':17,339 '即可':248 '原始文章':343 '參考資源':342 '只執行一次':146 '可能失效':213 '可能比自訂建構器有更高優先順序':211 '可能產生重複值':287 '可能重複值':176 '善用':252 '固定值':141,145 '型別':234 '執行緒安全':171,261 '多次建立有負擔':175 '天挑戰':347 '安裝套件':76 '完整':197 '官方文件':362,369 '實作':15,302 '實作範例請參考':199 '實作精確控制特定屬性的建構器':64 '實作類別':331 '實例化方式':168 '將自訂化與':317 '屬性':185 '屬性範圍控制':55 '建構器保持單一職責':282 '建構器或處理特殊型別的測試資料產生規則時使用':10 '建立可重用的泛型建構器':272 '建立支援多種數值型別的可重用建構器':75 '忽略建構器優先順序':276 '應能識別dataannot':118 '應該做':250 '應該避免':274 '所有物件相同值':147 '控制屬性範圍':140 '提供':335 '支援':191 '改進版數值範圍建構器':187 '效能':174 '效能更佳':177 '效能更好':262 '整合':48,319 '整合與泛型化建構器程式碼':341 '數值範圍建構器':19 '是':173 '最佳實踐':249 '會被攔截':240 '本技能內容提煉自':344 '本技能涵蓋':41 '本技能的前置知識':310 '核心技術':45 '概述':40 '正確':221 '每個建構器皆附完整實作與使用範例':196 '每個物件都重新計算':155 '每次建立新實例':169 '泛型化':188 '泛型化數值範圍建構器與擴充方法':305 '泛型化設計':74,271 '泛型化設計與流暢式擴充方法':20 '涵蓋':11,181 '無特定建構器':245 '特性':164 '理解':67 '產生':332 '產生自訂':329 '當需要自訂':8 '的優點':163 '的差異':72 '的進階自訂化功能':43 '的驗證屬性':83 '確保優先順序':266 '確保最高優先順序':222 '程式碼範本':289 '等多種型別':193 '等驗證屬性':53 '範例程式碼':358 '精確控制特定':183 '系列文章':348 '組合類別':334 '結合':325 '老派軟體工程師的測試修練':345 '能自動識別':81 '自動整合':13,79,297 '自動產生符合限制的資料':256 '自動識別':50 '自訂':62,179,300 '自訂化測試資料生成策略':39,353 '自訂數值建構器務必用':267 '與其他技能的關係':306 '與自訂資料生成':327 '處理差異':233 '被內建建構器攔截':214 '設定範例':338 '請參考':290 '讓您能根據業務需求精確控制測試資料的生成邏輯':44 '資料夾中的範例檔案':293 '輸出格式':328 '進階':38,352 '進階整合':324 '進階自訂化技術完整指南':7 '過度複雜的邏輯':281 '避免重複值':178 '避免重複值問題':260 '配合':58 '鐵人賽文章':354 '需先掌握基礎用法':311 '需用':241 '非執行緒安全':288","prices":[{"id":"9fcc16a1-b3f9-42bb-80c1-52a554ef2690","listingId":"720fbfca-d040-4cbb-8826-71da1b136f16","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:24.848Z"}],"sources":[{"listingId":"720fbfca-d040-4cbb-8826-71da1b136f16","source":"github","sourceId":"kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-autofixture-customization","sourceUrl":"https://github.com/kevintsengtw/dotnet-testing-agent-skills/tree/main/skills/dotnet-testing-autofixture-customization","isPrimary":false,"firstSeenAt":"2026-04-18T23:04:24.848Z","lastSeenAt":"2026-04-24T13:02:26.294Z"}],"details":{"listingId":"720fbfca-d040-4cbb-8826-71da1b136f16","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"kevintsengtw","slug":"dotnet-testing-autofixture-customization","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":"8642cae310f2c1940480fb068c5a82cd4fafe471","skill_md_path":"skills/dotnet-testing-autofixture-customization/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/kevintsengtw/dotnet-testing-agent-skills/tree/main/skills/dotnet-testing-autofixture-customization"},"layout":"multi","source":"github","category":"dotnet-testing-agent-skills","frontmatter":{"name":"dotnet-testing-autofixture-customization","description":"AutoFixture 進階自訂化技術完整指南。當需要自訂 AutoFixture 建構器或處理特殊型別的測試資料產生規則時使用。涵蓋 DataAnnotations 自動整合、ISpecimenBuilder 實作、優先順序管理。包含 DateTime/數值範圍建構器、泛型化設計與流暢式擴充方法。\nMake sure to use this skill whenever the user mentions AutoFixture customization, ISpecimenBuilder, DataAnnotations with AutoFixture, or custom builders for test data generation, even if they don't explicitly ask for customization guidance.\nKeywords: autofixture customization, autofixture customize, autofixture 自訂, specimen builder, ISpecimenBuilder, RandomDateTimeSequenceGenerator, NumericRangeBuilder, DataAnnotations autofixture, fixture.Customizations, Insert(0), 自訂建構器, NoSpecimen, 泛型化建構器"},"skills_sh_url":"https://skills.sh/kevintsengtw/dotnet-testing-agent-skills/dotnet-testing-autofixture-customization"},"updatedAt":"2026-04-24T13:02:26.294Z"}}