2012-01-07 40 views
6

我想創建單元測試代碼,模擬調用.Net System.IO類,所以我可以真正進行單元測試而不是依賴於文件系統。 我正在使用SystemWrapper類來環繞BCL類。如何使用.Net IO類創建可測試的代碼?

我想獲得一個簡單的例子,看看是否存在一個文件。

我遇到的問題是,在類注射的依賴不起作用,因爲實例的依賴(通過StructureMap)需要知道通過什麼構造函數的參數,這將不提供在那個時候,也有沒有默認的構造函數。

示例代碼:

// don't want to create dependency here like so 
//IFileInfoWrap fileInfoWrap = new FileInfoWrap(filename); 

// using service locator (anti-pattern?!) since it can't be 
// injected in this class 
var fileInfoWrap = ObjectFactory.GetInstance<IFileInfoWrap>(
    new ExplicitArguments(new Dictionary<string, object> 
    { 
     {"fileName", filename} 
    })); 

Console.WriteLine("File exists? {0}", fileInfoWrap.Exists); 

我不喜歡的是依賴沒有注入,ObjectFactory的不應該在這裏(但我認爲創建這個沒有別的辦法)。 ExplicitArguments使其變得混亂,參數名稱是一個魔術字符串。

,我得到這個工作StructureMap配置類需要知道我想用(我剛開始用StructureMap所以這可能不是設置它以正確的方式)顯式哪個構造:

ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.AssembliesFromPath("."); 
     scan.RegisterConcreteTypesAgainstTheFirstInterface(); 
     scan.WithDefaultConventions(); 
    }); 

    // use the correct constructor (string instead of FileInfo) 
    x.SelectConstructor(() => new FileInfoWrap(null as string)); 

    // setting the value of the constructor 
    x.For<IFileInfoWrap>() 
     .Use<FileInfoWrap>() 
     .Ctor<string>("fileName") 
     .Is(@"."); 
}); 

有沒有人找到更好的解決方案來創建System.IO類的可測試代碼? 我知道問題的一部分是在System.IO類的設計中。

+3

SystemWrapper主要含有極其漏抽象。對Streams,TextWriter,TextReader等進行IO建模將變得簡單和容易。這些類已經是抽象的,完全消除了對SystemWrapper的需求。 – 2012-01-07 10:38:52

+0

另一個投票流 – 2012-01-07 11:36:27

+0

我的發現與SystemWrapper是它似乎是一個很好的接口包裝,但它仍然是一個死衚衕,因爲原始類的工作方式。 例如,返回一個FileInfo對象數組不能被正確模擬。滾動我自己更簡化的包裝,它不需要模仿現有的類,而更多的工作會導致一個可行的解決方案恕我直言。 – 2012-01-08 06:48:37

回答

5

我非常成功地使用了一種方法,即爲System.IO和FCL的其他部分中找到的類型推出我自己的代理類型。例如。我想依靠System.IO.File。我創建了一個名爲System.IO.Proxies的庫並添加了一個具體類型File和一個接口IFile。接口IFile公開的成員相當於我從System.IO.File所需的全部成員,具體類型除了轉發方法調用System.IO.File之外什麼也不做。 System.IO.Proxies被排除在單元測試和代碼覆蓋範圍之外。在我的消費大會上,我僅依靠System.IO.Proxies獲得依賴關係,具體而言,我只依賴於IFile。通過這種方式,我可以輕鬆地嘲笑這種依賴關係,併爲我的消費組件獲得100%的代碼覆蓋率。

(請注意,這是我more general answer上一個問題的定製版本。)

+0

是的,那也是我結束的方式。 可以將呼叫委託給例如System.IO.FileInfo到一個單獨的類。 滾動你自己的代理確實需要爲每個類創建代理,這可能是一些工作,當然它可以與來自BCL類的所需功能一起增長。 同樣,當返回其他類型(FileInfo)時,應該在代理中創建所有必需屬性(名稱,全名,長度)。 有人會認爲這個問題已經'解決'了,已經避免了每個人的代理。 – 2012-01-07 14:10:20

+0

相當成功地使用了相同的方法。通常你不需要像_File_這樣的類的所有方法/屬性/事件。對於少數你確實需要編寫這樣的包裝很容易。 – 2012-01-07 18:09:33

相關問題