2010-02-11 52 views
6

我有一個輸出簡單報告文件的類。它從XML文件讀取一些記錄ID號碼:每個用於查找存儲在數據庫中的匹配記錄。然後將每條記錄的詳細信息寫入CSV文件。單元測試使用文件系統的類

我想知道 - 什麼是最好的方式來組織它,以便它很容易測試,但遵循封裝的原則?我認爲最好避免與文件系統交互,除非絕對必要,所以我正在處理Stream對象。單元測試時,我可以使用部分模擬對象來覆蓋讀取或寫入文件的位。

我也不確定何時/何地處理流而不會使單元測試變得棘手。看起來我可能不得不將這些流暴露給單元測試。

我的項目使用NHibernate進行數據訪問,Spring .NET進行依賴注入,Rhino.Mocks進行單元測試。

目前我有一些與此類似:

public class ReportBiz 
{ 
    //Access to repository, populated by Spring 
    internal ICardRequestDAO CardRequestData { get;set;} 

    //This normally returns a FileStream containing data from the XML file. When testing this is overridden by using a Rhino.Mocks partial mock and returns a MemoryStream 
    internal virtual Stream GetSourceStream() 
    { 
     //Load file and return a Stream 
     ... 
    } 

    //This normally returns a FileStream where CSV data is saved. When testing this is overridden by using a Rhino.Mocks partial mock and returns a MemoryStream 
    internal virtual Stream GetOutputStream() 
    { 
     //Create file where CSV data gets saved and return a Stream 
     ... 
    } 

    public void CreateReportFile() 
    { 
     Stream sourceStream = GetSourceStream(); 
     ... 

     //Create an XmlDocument instance using the stream 
     //For each XML element, get the corresponding record from the database 
     //Add record data to CSV stream  
     ... 
    } 
    } 

它會更好使用某種自定義的工廠或東西和流傳入構造?但是如果涉及到一些商業邏輯,如何呢?文件名是根據查詢結果確定的?

或者是整個文件訪問的東西不是問題?

道歉,如果我失去了明顯的東西。我會很感激任何建議。

+0

我需要問:你的XML是做什麼的?它是否只包含指向數據庫記錄的密鑰列表? – 2010-02-11 16:46:02

+0

除了數據庫密鑰外,它還包含我需要的三個與記錄相關的其他字段。這些也被用在報告中。 – James 2010-02-11 16:52:55

+0

相關:http://stackoverflow.com/questions/129036/unit-testing-code-with-a-file-system-dependency – 2010-02-11 16:58:44

回答

8

最簡單的方式讓文件存取模擬能夠同時保持控制權,支配資源的生命週期是一個StreamFactory注入類:

public class ReportBiz { 

    private IStreamFactory streamFactory; 

    public ReportBiz(IStreamFactory streamFactory) { 
     this.streamFactory = streamFactory 
    } 

    public void CreateReportFile() { 
     using(Stream stream = this.streamFactory.CreateStream()) { 
      // perform the important work! 
     } 
    } 
} 

,當有更多的業務邏輯參與,你的工廠方法可能有點更復雜,但不是很多:

public void CreateReportFile() { 
    string sourcePath = this.otherComponent.GetReportPath(); 
    using(Stream stream = this.streamFactory.CreateStream(sourcePath)) { 
     // perform the important work! 
    } 
} 
+0

感謝您的答覆。但是我對於如何驗證CSV報告文件流以確保我已經寫出正確的數據感到困惑。 如果輸出流是使用語句的一部分,那麼我無法測試它。我應該在課堂級別上引用它,並避免在ReportBiz實例本身處理之前進行處理? – James 2010-02-11 17:09:26

+0

我還沒有使用Rhino Mocks,但是在NMock中,我會注入一個模擬的'IStreamFactory',將調用存根到它的'CreateStream'方法,並使其返回一個模擬流,我將設置期望值'Stream.Write')來驗證我寫了正確的數據。 – 2010-02-11 19:31:45

2

你必須以某種方式嘲笑你的流,以避免它們暴露於測試,因爲你的業務邏輯的肉越來越輸入字符串和輸出st戒指正確。

在這個場景中的硬道理是你必須承認,你在你的數據流三個階段:

  • 讀取數據:解析數據是一個獨特的,獨特的問題
  • 的輸出內容:您必須驗證給定的正確數據,您具有正確的CSV字符串輸出
  • 將該內容寫入文件

老實說,整個文件寫入問題並不是什麼大問題--.NET Framework提供了經過很好測試的文件寫入功能,它超出了您的測試範圍。您遇到的大多數問題都是您吐出的CSV文件的準確性。

作爲一項預防措施,我建議不要使用自己的CSV編輯器。您應該嘗試查找已存在的CSV庫 - there are a lot of them over the net