Claude Code 上的 Agent Orchestration — AI 自動產生高品質 .NET 測試(3)

安裝與環境設定 — Unit Test Orchestrator 使用指南

從環境需求、安裝步驟,到跑出第一個測試工作流程。本文深入最常用、不需要 Docker 的 Unit Test Orchestrator — 七種使用情境、四階段流程,以及一個由淺入深、共六個階段的練習專案,讀完就能跑出你的第一個 Agent Orchestration 工作流程。

前言

前一篇解析了架構設計 — 為什麼 Orchestrator 是 Skill、bypassPermissions、計時 Hook、Writer 分割這些關鍵決策。這一篇開始進入實作:從環境安裝到實際跑出第一個測試工作流程。

原本想把四種 Orchestrator 的使用寫在同一篇,但內容太多:光是 Unit Test 一個 Orchestrator,就有七種使用情境、六個練習階段,還有完整的四階段工作流程細節,全部塞進一篇會太雜。所以拆成兩篇 — 這一篇先把共用的安裝與環境設定講清楚,再深入 Unit Test Orchestrator(最常用、不需要 Docker、最適合入門)。下一篇再處理需要額外環境的三個進階 Orchestrator。


環境需求

必要工具

工具說明
Claude Code CLI最新版本,claude 指令可在終端機執行
.NET SDK支援 net8.0 / net9.0 / net10.0,至少安裝一個版本
Node.js用於安裝 Agent Skills(npx skills install

進階測試額外需要(本篇用不到,下一篇會用到)

Unit Test 不需要 Docker。但如果你之後要用 Integration 或 Aspire Orchestrator,會需要:

工具適用測試說明
Docker DesktopIntegration、AspireTestcontainers / Aspire 容器編排需要
.NET Aspire workloadAspiredotnet workload install aspire

驗證工具已安裝

claude --version
dotnet --list-sdks
node --version

安裝步驟

步驟 1:Clone 儲存庫

git clone https://github.com/kevintsengtw/dotnet-testing-agent-orchestration-claude.git
cd dotnet-testing-agent-orchestration-claude

這個 repo 內建了所需的 .claude/ 目錄 — 4 個 Orchestrator Skill 與 dotnet-test 執行器、16 個 Subagent 定義檔,以及計時 Hook 腳本。

步驟 2:安裝 Agent Skills

外部的 Agent Skills 提供各種 .NET 測試技術的知識庫(AutoFixture、NSubstitute、Testcontainers 等),需從 dotnet-testing-agent-skills 安裝:

npx skills install dotnet-testing-agent-skills

安裝完成後,這 29 個 Skills 會安裝到 Claude Code 的用戶 Skills 目錄,供所有使用 Claude Code 的專案共用。

驗證:在 Claude Code 對話中輸入 /,確認清單中可看到 dotnet-testing-autofixture-basicsdotnet-testing-nsubstitute-mocking 等 Skills。

步驟 3:確認 .claude/ 目錄結構

完成步驟 1、2 後,.claude/ 的預期結構如下:

.claude/
├── agents/                              ← repo 內建(16 個 Subagent)
│   ├── dotnet-testing-analyzer.md        Unit 組
│   ├── dotnet-testing-writer.md
│   ├── dotnet-testing-executor.md
│   ├── dotnet-testing-reviewer.md
│   ├── dotnet-testing-advanced-integration-*.md   Integration 組(4 個)
│   ├── dotnet-testing-advanced-aspire-*.md         Aspire 組(4 個)
│   └── dotnet-testing-advanced-tunit-*.md          TUnit 組(4 個)
│
├── hooks/                               ← repo 內建(計時 Hook)
│   ├── dotnet-testing-agent-timer-pre.sh
│   ├── dotnet-testing-agent-timer-post.sh
│   └── install-hooks.js
│
└── skills/
    │   ── repo 內建(5 個)──
    ├── dotnet-test/                      .NET 測試執行器
    ├── dotnet-testing-orchestrator-unit/
    ├── dotnet-testing-orchestrator-integration/
    ├── dotnet-testing-orchestrator-aspire/
    ├── dotnet-testing-orchestrator-tunit/
    │
    │   ── npx skills install 安裝後新增(29 個)──
    ├── dotnet-testing-autofixture-basics/
    ├── dotnet-testing-nsubstitute-mocking/
    └── ...(其餘 27 個 Agent Skills)

repo 內建的是 4 個 Orchestrator Skill 加 1 個 dotnet-test 執行器(共 5 個 Skill)與 16 個 Subagent;另外 29 個 Agent Skills 由步驟 2 安裝,因此 .claude/skills/ 下最終會有 34 個 Skill。

步驟 4:安裝計時 Hook(可選,但強烈建議)

計時 Hook 會在每個 Subagent 執行前後自動追蹤耗時,並把時間資訊注入到 Claude 的 context 中。技術上它是可選的 — 沒裝工作流程照樣能跑;但強烈建議裝上:有了每個階段的耗時,你才看得出時間花在哪、哪個 Subagent 是瓶頸,這在跑比較久的 Integration、Aspire 工作流程時特別有用。它只需要裝一次,幾乎沒有不裝的理由。

在 repo 根目錄執行:

node .claude/hooks/install-hooks.js

步驟 5:驗證安裝

啟動 Claude Code 後,在對話中輸入 /,確認以下斜線指令可用:

斜線指令對應 Orchestrator
/dotnet-testing-orchestrator-unit單元測試
/dotnet-testing-orchestrator-integration整合測試
/dotnet-testing-orchestrator-aspireAspire 測試
/dotnet-testing-orchestrator-tunitTUnit 測試

四個指令都出現在清單中,就表示安裝完成。


在 VS Code 裡執行:先開好 Bypass permissions

上一篇提過,每個 Subagent 的定義裡都設了 bypassPermissions: true,讓 Executor 跑 dotnet builddotnet test 時不必每個指令都等你確認。但如果你用的是 VS Code 的 Claude 擴充套件,擴充套件本身還有一層權限把關 — 預設每執行一個指令都會跳出確認,四階段流程會被一直打斷。要讓它順順跑完,有兩個地方要設定。

第一,打開 VS Code 設定(Settings),搜尋 claude,把 Claude Code: Allow Dangerously Skip Permissions 勾起來。

第二,光開設定還不夠 — 還要在 chat panel 把模式切到 Bypass permissions(按 Shift + Tab 可以循環切換各種模式)。切到這個模式後,Claude 執行指令前就不會再逐一要求確認。

要提醒的是,bypass 顧名思義是跳過所有確認,官方建議只在隔離環境(容器、VM、沙箱)使用。這套測試工作流程的指令範圍很明確 — 建置、跑測試、在測試專案內寫檔 — 風險可控,但你還是要清楚它在替你做什麼。另外,這是 Claude Code 標準的權限模式,不限特定付費方案;如果你在設定裡看不到、或切不過去,通常是被使用者自己的設定或(Team / Enterprise)組織的管理設定停用了。


Unit Test Orchestrator 使用

環境就緒後,我們從最常用的 Unit Test Orchestrator 開始。它適用於任何需要為 .NET 類別產生 xUnit 單元測試的情境 — 純函式計算、有 Mock 依賴的服務類別、FluentValidation 驗證器、含時間或檔案系統抽象的類別。

測試技術棧:xUnit 2.9 + NSubstitute + AutoFixture + AwesomeAssertions + Bogus + FakeTimeProvider + MockFileSystem。

基本操作

在 Claude Code 工作階段中輸入斜線指令觸發 Orchestrator,並提供目標類別的資訊:

/dotnet-testing-orchestrator-unit 為 OrderService 撰寫單元測試。
被測試目標:src/MyApp.Core/Services/OrderService.cs
測試專案:tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj
說明:(可選,用於補充特殊需求)

指令觸發後,Orchestrator 會依序自動啟動四個 Subagent:Analyzer → Writer → Executor → Reviewer,全程無需手動介入。

七種使用情境

Unit Test Orchestrator 會根據被測類別的特性,自動決定要用哪些測試技術。以下七種情境涵蓋了大部分的單元測試需求。

情境 1:純函式計算類別

目標類別無外部依賴,只有純計算邏輯(如溫度轉換、數值運算)。

「為 TemperatureConverter 撰寫單元測試,純函式溫度轉換類別,無外部依賴」

Analyzer 判斷類別無建構子依賴,只用基礎技能;Writer 不引入 Mock,直接以 [Fact] / [Theory] 測試純計算邏輯。命名範例:CelsiusToFahrenheit_攝氏0度_應回傳華氏32度

情境 2:有 Mock 依賴的服務類別

建構子注入一個或多個介面(如 IWeatherServiceINotificationService),需要 Mock 隔離外部依賴。

「為 WeatherAlertService 撰寫單元測試」

Analyzer 偵測到介面依賴,要求載入 NSubstitute 技能;Writer 用 Substitute.For<IXxx>() 建立 Mock 並設定 Stub 行為,非同步方法用 await 正確測試。

情境 3:AutoFixture + Bogus 測試資料

操作的模型包含循環參考或複雜結構(如 EmployeeDepartment),需要自動產生測試資料。

「為 EmployeeService 撰寫單元測試,Employee 模型含循環參考,需要 AutoFixture + Bogus 產生測試資料」

Writer 用 OmitOnRecursionBehavior 處理循環參考,擬真假資料透過 Bogus.Faker 產生。

情境 4:FakeTimeProvider 時間依賴

建構子注入 TimeProvider,方法內部依賴目前時間判斷(如訂閱有效期、排程觸發)。

「為 SubscriptionService 撰寫單元測試」

Writer 用 FakeTimeProvider 在測試中凍結或快轉時間。命名範例:IsSubscriptionActive_訂閱期間內_應回傳true

情境 5:MockFileSystem 檔案系統抽象

建構子注入 IFileSystem,操作檔案讀寫或目錄處理。

「為 ConfigurationLoader 的所有公開方法撰寫單元測試」

Writer 用 MockFileSystem 在記憶體中建立虛擬檔案與目錄,測試涵蓋檔案存在/不存在、讀寫成功/失敗、路徑異常等情境。

情境 6:FluentValidation 驗證器

目標類別繼承 AbstractValidator<T>,需用 FluentValidation TestHelper 模式測試驗證規則。

「為 OrderValidator 撰寫單元測試」

Analyzer 將 targetType 設為 validator;Writer 用 validator.TestValidate(model) 搭配 ShouldHaveValidationErrorFor() / ShouldNotHaveValidationErrorFor()。值得注意的是,Validator 類別永遠使用單一 Writer,不會被分割,以確保驗證規則的一致性。

情境 7:多目標類別平行處理

一次指定多個目標類別,Orchestrator 自動以平行方式分析與撰寫。

「為 OrderProcessingService、WeatherAlertService 撰寫單元測試」

Orchestrator 平行啟動兩個 Analyzer 與兩個 Writer,但 Executor 循序執行(共用同一測試專案,避免 dotnet build 衝突),最後彙整呈現概覽表格與各目標詳細結果。

四階段工作流程

每次觸發指令後,Orchestrator 依序執行四個階段:

Phase 1 — Analyzer 分析:讀取被測目標原始碼,判斷類別類型(service / validator / legacy),識別建構子依賴(I* 介面要 Mock、TimeProvider 用 FakeTimeProvider、IFileSystem 用 MockFileSystem),評估需要哪些 Agent Skills,估算各方法的測試情境數量,產出 JSON 分析報告。

Phase 2 — Writer 撰寫:讀取 Analyzer 的交接 JSON,按需載入對應 Agent Skills,按中文三段式命名(方法名_情境描述_預期結果)產生測試。當方法數 > 5 或情境數 > 20 時,會分割為兩個平行 Writer,且兩者的斷言風格、using 排列、初始化方式必須完全一致。所有斷言使用 AwesomeAssertions(.Should()),禁止 xUnit 原生 Assert.*

Phase 3 — Executor 建置與執行:透過 repo 內建的 dotnet-test Skill 以 build-first 流程執行 — 先 dotnet build 確認可編譯,再用 dotnet test --no-build 確認通過,必要時以 --filter 鎖定特定測試。遇到編譯錯誤或測試失敗,自行分析並修正,最多 3 輪,超過則回報失敗。

Phase 4 — Reviewer 審查:讀取測試程式碼與三個交接檔案,審查命名規範、斷言品質、單一行為原則、Mock 設定、AutoFixture 一致性、覆蓋完整性,產出評分與改善建議。Orchestrator 呈現完整報告後,等待使用者決定是否啟動修改流程(Writer 修改 → Executor 重新執行 → Reviewer 重新審查)。

實際跑一次:SubscriptionService

講完四階段,來看實際跑一次長什麼樣。這裡用練習專案裡的 SubscriptionService(就是情境 4 那個依賴 TimeProvider 的類別)當例子,下這個指令:

/dotnet-testing-orchestrator-unit 為 SubscriptionService 撰寫單元測試。
被測試目標:samples/unit/practice/src/Practice.Core/Services/SubscriptionService.cs
測試專案:samples/unit/practice/tests/Practice.Core.Tests/Practice.Core.Tests.csproj

觸發後,Orchestrator 會先做 Phase 0 前置清理(確認沒有殘留的 .orchestrator/ 目錄),再進入階段 1,把 Analyzer 委派出去。

階段 1 的 Analyzer 分析出這個類別有 6 個方法、依賴一個 TimeProvider,判斷需要載入哪幾個 Agent Skills,並寫出 analysis.json。因為方法數與情境數超過門檻,這裡觸發了 Writer 分割 — 用貪心分組把方法拆成兩組,啟動兩個平行 Writer(階段 2)。

兩個 Writer 寫完後進入階段 3,Executor 以 build-first 流程執行 — 先 dotnet build 確認可編譯(建置成功、零警告零錯誤),再 dotnet test 跑測試。

這次測試初次建置就全數通過、零修正輪次。接著階段 4 的 Reviewer 審查品質,最後 Orchestrator 執行 Phase 5 後置清理,把整個 .orchestrator/ 暫存目錄清掉。

最後 Orchestrator 會給出一份完整報告:產出了哪些測試檔案、執行結果、品質評分與改善建議。

值得一提的是,這次 Reviewer 抓到了 Analyzer 的一個疏漏 — 有個公開方法 GetSubscriptionStatus 根本沒被測到(Analyzer 只算了 6 個方法,實際有 7 個),並列出建議補上的測試案例。這正是四階段裡 Reviewer 這一關的價值:它會回頭挑出前面階段漏掉的東西,而不是測完就算數。

報告最後那張「各階段耗時」表,就是前面步驟 4 那個計時 Hook 的產物 — 一眼就看得出時間花在哪(這次 Writer 最久)。看完報告,Orchestrator 會停下來等你決定要不要套用 Reviewer 的修改建議;要套用的話,就會進入「Writer 修改 → Executor 重新執行 → Reviewer 重新審查」的循環。

練習專案

repo 內附了一個練習專案在 samples/unit/practice/,由淺入深分為六個學習階段:

Phase目標類別學習重點
Phase 1TemperatureConverterAAA Pattern、[Fact] / [Theory]、AwesomeAssertions
Phase 2WeatherAlertServiceNSubstitute Mock/Stub、非同步方法測試
Phase 3EmployeeServiceAutoFixture、循環參考處理、Bogus 假資料
Phase 4SubscriptionServiceConfigurationLoaderFakeTimeProvider、MockFileSystem
Phase 5OrderProcessingService多 Mock 協調的複雜業務邏輯
Phase 6LegacyReportGenerator遺留程式碼識別、重構策略、Characterization Test

練習專案支援 net8.0 / net9.0 / net10.0 三個版本。練習產生的測試檔案僅供練習,不應 commit,要還原初始狀態可執行:

git checkout -- samples/unit/practice/tests/

常見問題排查

Agent Skills 未載入:Writer 找不到 dotnet-testing-autofixture-basics 等技能,或斜線指令無法使用。重新執行 npx skills install dotnet-testing-agent-skills,安裝後重啟 Claude Code 工作階段。

Writer 沒有觸發分割:當方法數超過 5 或情境數超過 20 時應自動分割為兩個平行 Writer。若沒分割,可能是 Analyzer 估算的情境數偏低,可在指令中補充說明該類別的複雜度提示。注意 Validator 類別永遠不分割。

AutoFixture 循環參考錯誤dotnet test 出現 ObjectCreationException。在 Fixture 初始化時加入 OmitOnRecursionBehavior,或改用 Builder 方式手動建立含循環參考的物件。

xUnit Theory 參數型別問題decimal 無法直接用於 [InlineData](xUnit 限制),編譯會出現 An attribute argument must be a constant expression。改用 [MemberData] 傳遞 decimal 參數。

斜線指令無法使用:確認 .claude/skills/ 下各目錄有 SKILL.md、目錄名稱完全吻合,重啟 Claude Code 讓 Skills 重新載入。


附帶一提:跟 Copilot 版的一次耗時對照

這套測試工作流程,我更早是在 GitHub Copilot 上做的(dotnet-testing-agent-orchestration,最後一個版本停在 v2.0.0)。那個版本從 v1 改版時,其中一項重點就是把分階段耗時內建進流程,所以它跟 Claude 版一樣會輸出每個階段的耗時 — 剛好可以把兩邊各跑一次的數字放在一起看。

要先說清楚,這不是嚴謹的 benchmark:兩次跑的被測類別不一樣(Claude 版是前面那個 SubscriptionService,Copilot v2.0.0 版是練習專案裡的 OrderProcessingService),平台與模型也不同(一邊跑在 Claude Code、一邊跑在 GitHub Copilot,底層模型一個是 Claude、一個是 GPT-5.3-Codex)。所以下面的數字只能當作「各自跑一次的體感」,不是控制變因後的對照。

階段Claude 版(SubscriptionService)Copilot v2.0.0 版(OrderProcessingService)
Analyzer1 分 18 秒2 分 55 秒
Writer2 分 25 秒2 分 25 秒
Executor52 秒1 分 30 秒
Reviewer1 分 8 秒1 分 52 秒
總計5 分 43 秒9 分 46 秒

(Copilot 版的數字取自 v2.0.0 timing log 的各階段起訖時間換算,Claude 版取自前面那次 SubscriptionService 的各階段耗時表。)

就算把「被測類別不同」這個變因放進去,整體量級的差距還是看得出來 — 這次 Claude 版的總時間大約是 Copilot v2.0.0 那次的六成,差最多的是 Analyzer 這個分析階段。Writer 兩邊剛好都是 2 分 25 秒,則純粹是巧合。但還是回到那句話:各只跑一次、被測類別又不同,這張表看個大概的量級就好,真要比較得固定被測對象、各跑多次才算數。


小結

這一篇把安裝走了一遍 — clone repo、裝 Agent Skills、(強烈建議)裝計時 Hook、驗證斜線指令 — 然後深入了最常用的 Unit Test Orchestrator:七種使用情境、四階段工作流程,以及附帶的六階段練習專案。

選 Unit Test 當作入門是有原因的:它不需要 Docker、涵蓋的測試技術最廣(從純函式到 Mock、AutoFixture、TimeProvider、MockFileSystem、FluentValidation),跑一輪下來就能對整個 Agent Orchestration 的運作有完整體感。練習專案的六個 Phase 也是按這個邏輯設計的,建議照順序跑一遍。

下一篇會接著介紹其餘三個 Orchestrator — Integration、Aspire、TUnit。它們需要額外的環境(Docker、Aspire workload)或不同的執行方式,但共用同一套安裝基礎與四階段架構。


參考資源

純粹是在寫興趣的,用寫程式、寫文章來抒解工作壓力