C# 使用 System.IO.Abstractions 套件來模擬檔案

筆者平時在開發時通常都會加上單元測試,因為現在寫測試很容易,與其每次修改都要再次手動測試,還不如寫一次自動測試。只是通常單元測試覆蓋率都不會高到哪裡去,只有比較重要的地方會寫單元測試,一方面是時間不夠,另一方面是不容易測試。例如檔案讀取
或許有些人會覺得檔案讀取還需要測試?! 不過這個套件在 NuGet 上有超過 4200 萬的下載,代表這個測試也不是完全不重要。

安裝

先使用 NuGet 安裝 System.IO.Abstractions 套件,或是使用 .NET CLI 執行以下指令安裝:
	
dotnet add package System.IO.Abstractions
    

註: 此套件還有一個名稱是 TestableIO.System.IO.Abstractions ,他多了 TestableIO 前綴,用來用於辨識是非官方。官方說明兩個是相同的,不過在筆者的測試下發現 TestableIO.System.IO.Abstractions 一定要再裝他的 TestingHelpers 才能夠正常使用,不然會找不到 FileSystem 。

再使用 NuGet 安裝 System.IO.Abstractions.TestingHelpers 套件,或是使用 .NET CLI 執行以下指令安裝
	
dotnet add package System.IO.Abstractions.TestingHelpers
    

System.IO.Abstractions 套件是新增檔案相關的介面,而 System.IO.Abstractions.TestingHelpers 套件則是用於模擬檔案相關操作

範例程式碼

沒有參數的建構子使用系統的 FileSystem ,然後多加了一個有參數的建構子,方便測試時使用。
    
using System.IO.Abstractions;

public class MyService
{
    private readonly IFileSystem _fileSystem;

    public MyService()
    {
        _fileSystem = new FileSystem();
    }

    public MyService(IFileSystem fileSystem)
    {
        _fileSystem = fileSystem;
    }

    public string ReadFile(string path)
    {
        return _fileSystem.File.ReadAllText(path);
    }
}
    

一般程式碼直接使用系統的 FileSystem (已經寫在無參數的建構子,不須額外傳入)
    
MyService myService = new MyService();

string file = myService.ReadFile(@"C:\Users\ruyut\Desktop\my.json");
Console.WriteLine(file);
    

測試時使用 MockFileSystem 建立模擬的檔案,裡面傳入測試內容,讀取時不會去讀取到實際檔案,而是自訂的內容。
    
var mockFileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
    {
        { @"C:\Users\ruyut\Desktop\my.json", new MockFileData("這是檔案的內容") },
    }
);


MyService myService = new MyService(mockFileSystem);

string file = myService.ReadFile(@"C:\Users\ruyut\Desktop\my.json");
Console.WriteLine(file);
    

若沒有先在 MockFileSystem 中放入檔案路徑,就會視為沒有此檔案,模擬找不到檔案時的情境,拋出的例外如下:
    
17360 C:/Users/ruyut/Documents/RiderProjects/2023/test/ConsoleAppSystem.IO.Abstractions/ConsoleAppSystem.IO.Abstractions/bin/Debug/net6.0/ConsoleAppSystem.IO.Abstractions.exe
Unhandled exception. System.IO.FileNotFoundException: Could not find file 'C:\Users\ruyut\Desktop\my.json'.
File name: 'C:\Users\ruyut\Desktop\my.json'
   at System.IO.Abstractions.TestingHelpers.MockFile.ReadAllText(String path, Encoding encoding)
   at System.IO.Abstractions.TestingHelpers.MockFile.ReadAllText(String path)
   at ConsoleAppSystem.IO.Abstractions.MyService.ReadFile(String path) in C:\Users\ruyut\Documents\RiderProjects\2023\test\ConsoleAppSystem.IO.Abstractions\ConsoleAppSystem.IO.Abstractions\MyService.cs:line 21

   at Program.<Main>$(String[] args) in C:\Users\ruyut\Documents\RiderProjects\2023\test\ConsoleAppSystem.IO.Abstractions\ConsoleAppSystem.IO.Abstractions\Program.cs:line 13

Process finished with exit code -532,462,766.


    



參考資料:
Github - TestableIO/System.IO.Abstractions

留言