Skip to content

Commit f486b56

Browse files
perditavojoCopilot
andcommitted
docs(testing): 同步測試規範與 README 至今日測試擴充異動
docs/engineering/testing.md: - 第 2 節補充 MTP 原生模式的 Coverage 收集指令 (dotnet test --coverage --coverage-output-format cobertura) - 第 2 節加入 MTP 先決條件說明 (global.json runner = Microsoft.Testing.Platform、UseMicrosoftTestingPlatformRunner) - 新增第 5 節:xUnit1051 / xUnit1031 分析器規則 (CancellationToken 來源、禁止 .Result/.Wait()) - 第 6 節(原第 5 節)CI 步驟更新,反映 coverage + ReportGenerator 流程 tests/InputBox.Tests/README.md: - 測試類別表格新增 9 個新類別,更新 3 個現有類別計數 - 總計從 72 更新為 188 - 隔離說明章節新增 InputHistoryService 說明 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fb22c19 commit f486b56

2 files changed

Lines changed: 44 additions & 9 deletions

File tree

docs/engineering/testing.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,16 @@ dotnet test tests/InputBox.Tests/InputBox.Tests.csproj
1515
1616
# 加入詳細輸出
1717
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj --logger "console;verbosity=detailed"
18+
19+
# 收集 Code Coverage(MTP 原生模式,同 CI)
20+
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj -c Release --no-build `
21+
--coverage `
22+
--coverage-output-format cobertura `
23+
--coverage-output coverage.cobertura.xml
1824
```
1925

26+
> **前置條件**`global.json` 必須設定 `"test": { "runner": "Microsoft.Testing.Platform" }`,Coverage 套件使用 `Microsoft.Testing.Extensions.CodeCoverage`(非 coverlet.collector,兩者與 xUnit v3 MTP 不相容)。
27+
2028
## 3. 檔案系統隔離模式(Filesystem Isolation)
2129

2230
凡是被測目標的方法會**讀寫使用者資料目錄**(如 `%AppData%\InputBox\*.json`),測試類別必須實作 `IDisposable` 的備份/還原模式:
@@ -63,12 +71,30 @@ Validate_InitialDelayFramesZero_Throws
6371

6472
每個 `[Fact]` 方法**必須**加上繁體中文 `/// <summary>` XML 文件,說明該測試驗證的行為意圖,而非僅重述方法名稱。
6573

66-
## 5. CI 整合
74+
## 5. xUnit Analyzer 規則
75+
76+
以下 analyzer 規則在 CI 中視為錯誤,必須遵守:
77+
78+
| 規則 | 說明 | 正確做法 |
79+
|---|---|---|
80+
| **xUnit1051** | 非同步測試不得使用 `CancellationToken.None` | 改用 `TestContext.Current.CancellationToken` |
81+
| **xUnit1031** | 不得在測試中使用阻塞式 Task 操作(`.Result``.Wait()``.GetAwaiter().GetResult()`| 改用 `await` |
82+
83+
```csharp
84+
// ✗ 違規
85+
await Task.Delay(100, CancellationToken.None);
86+
87+
// ✓ 正確
88+
await Task.Delay(100, TestContext.Current.CancellationToken);
89+
```
90+
91+
## 6. CI 整合
6792

6893
測試在 GitHub Actions 的 `ci.yml` 中自動執行,流程如下:
6994

7095
1. 建置主專案(`src/InputBox`
7196
2. 建置測試專案(`tests/InputBox.Tests`
72-
3. 執行測試(`dotnet test -c Release --no-build`
97+
3. 執行測試並收集覆蓋率(`dotnet test -c Release --no-build --coverage ...`
98+
4. 使用 ReportGenerator 產生 HTML / Cobertura 報告並上傳 Artifact
7399

74100
每次 push 到任何分支,以及 PR 至 `main`,均會觸發。Runner 為 `windows-latest`

tests/InputBox.Tests/README.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@ InputBox 的單元測試專案,使用 [xUnit v3](https://xunit.net/) 撰寫。
66

77
| 測試類別 | 被測目標 | 測試數 |
88
|---|---|---|
9-
| `AppSettingsTests` | `AppSettings` 關鍵常數(安全邊界、A11y 上限) | 7 |
9+
| `AnnouncementServiceTests` | `AnnouncementService` 訊息排隊與 Dispose 行為 | 4 |
10+
| `AppSettingsTests` | `AppSettings` 關鍵常數(安全邊界、A11y 上限、Clamp 行為) | 22 |
11+
| `DialogLayoutHelperTests` | `DialogLayoutHelper` 對話框版面輔助方法 | 9 |
12+
| `FloatingPointFormatConverterTests` | `FloatingPointFormatConverter` 字串轉換 | 16 |
13+
| `FormInputStateManagerTests` | `FormInputStateManager` 輸入狀態切換 | 15 |
1014
| `GamepadDeadzoneHysteresisTests` | `GamepadDeadzoneHysteresis.ResolveDirection`(int / float 多載) | 12 |
1115
| `GamepadRepeatSettingsTests` | `GamepadRepeatSettings` 預設值與 `Validate()` | 7 |
1216
| `GamepadRepeatStateMachineTests` | `GamepadRepeatStateMachine.AdvanceDirectionRepeat` / `AdvanceHeldRepeat` | 11 |
13-
| `GamepadSignalEvaluatorTests` | `GamepadSignalEvaluator.IsActive` / `IsIdle`(int / float 多載) | 12 |
14-
| `PhraseServiceTests` | `PhraseService` CRUD(Add / Update / Remove / MoveUp / MoveDown) | 23 |
15-
| **合計** | | **72** |
17+
| `GamepadSignalEvaluatorTests` | `GamepadSignalEvaluator.IsActive` / `IsIdle`(int / float 多載) | 13 |
18+
| `GaussianDelayHelperTests` | `GaussianDelayHelper` 延遲計算 | 5 |
19+
| `InputBoxLayoutManagerTests` | `InputBoxLayoutManager` 版面管理 | 4 |
20+
| `InputHistoryServiceTests` | `InputHistoryService` 歷程記錄 CRUD | 13 |
21+
| `PhraseServiceTests` | `PhraseService` CRUD 與匯出/匯入 | 35 |
22+
| `TaskExtensionsTests` | `TaskExtensions` CTS 擴充方法 | 9 |
23+
| `VibrationPatternsTests` | `VibrationPatterns` 震動模式常數與行為 | 13 |
24+
| **合計** | | **188** |
1625

1726
## 執行測試
1827

@@ -28,10 +37,10 @@ dotnet test tests/InputBox.Tests/InputBox.Tests.csproj --logger "console;verbosi
2837

2938
## 注意事項
3039

31-
### PhraseService 測試的資料隔離
40+
### PhraseService / InputHistoryService 測試的資料隔離
3241

33-
`PhraseService` 的 CRUD 方法會寫入使用者的 `%AppData%\InputBox\phrases.json`
34-
為了避免測試污染真實資料,`PhraseServiceTests` 採用以下策略
42+
`PhraseService` `InputHistoryService` 的方法會寫入使用者的 `%AppData%\InputBox\` 目錄下的 JSON 檔案
43+
為了避免測試污染真實資料,這些測試類別採用以下策略
3544

3645
- **建構子**:若檔案存在,複製至 `phrases.json.testbackup`
3746
- **Dispose**:測試結束後自動還原備份(或刪除測試產生的檔案)

0 commit comments

Comments
 (0)