# Kevintsengtw Dotnet Testing Agent Skills Dotnet Testing Filesystem Testing Abstractions

> 檔案系統測試：使用 System.IO.Abstractions 模擬檔案操作

- Skill: `tomevault-io/kevintsengtw-dotnet-testing-agent-skills-dotnet-testing-file` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/kevintsengtw-dotnet-testing-agent-skills-dotnet-testing-file`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/kevintsengtw-dotnet-testing-agent-skills-dotnet-testing-file/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/kevintsengtw-dotnet-testing-agent-skills-dotnet-testing-file

---


# 檔案系統測試：使用 System.IO.Abstractions 模擬檔案操作

## 核心原則

### 1. 檔案系統相依性的根本問題

傳統直接使用 `System.IO` 靜態類別的程式碼難以測試，原因包括：

- **速度問題**：實際磁碟 IO 比記憶體操作慢 10-100 倍
- **環境相依**：測試結果受檔案系統狀態、權限、路徑影響
- **副作用**：測試會在磁碟上留下痕跡，影響其他測試
- **並行問題**：多個測試同時操作同一檔案會產生競爭條件
- **錯誤模擬困難**：難以模擬權限不足、磁碟空間不足等異常

### 2. System.IO.Abstractions 解決方案

將 System.IO 靜態類別包裝成介面的套件，支援依賴注入和測試替身。

**必要 NuGet 套件**：

```xml
<!-- 正式環境 -->
<PackageReference Include="System.IO.Abstractions" Version="22.1.0" />

<!-- 測試專案 -->
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="22.1.0" />
```

### 3. 重構步驟

**步驟一**：將直接使用靜態類別的程式碼改為依賴 `IFileSystem`

```csharp
// ❌ 重構前（不可測試）
public class ConfigService
{
    public string LoadConfig(string path) => File.ReadAllText(path);
}

// ✅ 重構後（可測試）
public class ConfigService
{
    private readonly IFileSystem _fileSystem;
    public ConfigService(IFileSystem fileSystem) => _fileSystem = fileSystem;
    public string LoadConfig(string path) => _fileSystem.File.ReadAllText(path);
}
```

**步驟二**：在 DI 容器中註冊真實實作

```csharp
services.AddSingleton<IFileSystem, FileSystem>();
```

**步驟三**：在測試中使用 MockFileSystem

```csharp
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
    ["config.json"] = new MockFileData("{ \"key\": \"value\" }")
});
var service = new ConfigService(mockFs);
```

## MockFileSystem 測試模式

涵蓋四種核心測試模式：預設檔案狀態建立、驗證寫入結果、目錄操作測試、使用 NSubstitute 模擬 IO 異常（UnauthorizedAccessException 等）。另含進階技巧：串流操作測試、檔案資訊查詢測試、備份檔案測試。

> 完整 MockFileSystem 測試模式與進階技巧請參考 [references/mockfilesystem-patterns.md](references/mockfilesystem-patterns.md)

## 最佳實踐

### 應該這樣做

1. **使用 Path.Combine 處理路徑** — `_fileSystem.Path.Combine("configs", "app.json")`
2. **防禦性檢查檔案存在性** — 在讀取前先檢查 `_fileSystem.File.Exists()`
3. **自動建立必要目錄** — 寫入前確保目錄存在
4. **妥善處理各種 IO 異常** — UnauthorizedAccessException、IOException、DirectoryNotFoundException
5. **每個測試使用獨立的 MockFileSystem** — 確保測試隔離

### 應該避免

1. **硬編碼路徑分隔符號** — 使用 `Path.Combine` 取代 `\\` 或 `/`
2. **在單元測試中使用真實檔案系統** — 使用 MockFileSystem
3. **忽略例外處理** — 不要假設檔案一定存在

## 效能考量

- **MockFileSystem 速度**：比真實檔案操作快 10-100 倍
- **記憶體使用**：只建立測試必需的檔案，避免模擬超大檔案

## 實務整合範例

請參考 `templates/` 目錄下的完整實作：

- `configmanager-service.cs` - 設定檔管理服務（載入/儲存/備份）
- `filemanager-service.cs` - 檔案管理服務（複製/目錄操作/錯誤處理）

## 輸出格式

- 產生使用 IFileSystem 介面的服務類別
- 產生使用 MockFileSystem 的測試類別
- 包含檔案讀寫、目錄操作、路徑處理測試範例
- 提供 .csproj 套件參考（System.IO.Abstractions、System.IO.Abstractions.TestingHelpers）

## 參考資源

### 原始文章

本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章：

- **Day 17 - 檔案與 IO 測試：使用 System.IO.Abstractions 模擬檔案系統**
  - 鐵人賽文章：https://ithelp.ithome.com.tw/articles/10375981
  - 範例程式碼：https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day17

### 官方文件

- [System.IO.Abstractions GitHub](https://github.com/TestableIO/System.IO.Abstractions)
- [System.IO.Abstractions NuGet](https://www.nuget.org/packages/System.IO.Abstractions/)
- [TestingHelpers NuGet](https://www.nuget.org/packages/System.IO.Abstractions.TestingHelpers/)

### 相關技能

- `nsubstitute-mocking` - 測試替身與模擬
- `unit-test-fundamentals` - 單元測試基礎

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/kevintsengtw) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-11 -->

