2008-09-20 79 views
22

最近我一直在研究的程序中的一個常見任務是以某種方式修改文本文件。 (嘿,我是在Linux上,一切是一個文件,而我做大型的系統管理員。)單元測試文件修改

但文件中的代碼修改可能無法在我的桌面盒存在。如果它在我的桌面上,我可能不想修改它。

我讀過關於深入Python單元測試,這是很清楚我想要測試一個十進制轉換爲羅馬數字(在DintoP的例子)的應用程序時做的。測試很好地獨立。你不需要驗證程序是否打印正確的東西,你只需要驗證函數是否將正確的輸出返回給定的輸入。

在我的情況,但是,我們需要測試程序正確地修改其環境。這是我想出來的:

1)創建標準位置中的「原始」的文件,或許是/ tmp目錄。

2)運行該修改文件,路徑傳遞到/ tmp中文件的功能。

3)驗證/ tmp中的文件是否正確更改;通過/失敗單元測試相應。

這對我來說似乎很笨拙。 (如果你想驗證文件的備份副本是否正確創建,那麼還可以獲得更多的信息,等等)有沒有人想出了一個更好的方法?

回答

14

你說的是一次測試過多。如果你開始嘗試通過說「讓我們確認它正確地修改它的環境」來攻擊測試問題,那麼註定會失敗。環境有數十甚至數百萬種潛在變化。

相反,看看你的程序的作品(「單位」)。例如,你將有一個函數來確定文件必須寫入哪裏?該功能的輸入是什麼?也許一個環境變量,也許從配置文件中讀取一些值?測試這個函數,並且實際上並沒有做任何修改文件系統的操作。不要傳遞它「現實」的價值觀,通過它很容易驗證的價值觀。創建一個臨時目錄,用你的測試的setUp方法中的文件填充它。

然後測試寫入文件的代碼。只要確保它正在寫入正確的內容文件內容即可。甚至不寫入真正的文件系統!您不需要爲此製作「假」文件對象,只需使用Python便捷的StringIO模塊;他們是「文件」界面的「真正的」實現,它們只是你的程序實際上不會寫入的內容。

最終,您將不得不測試最終的,一切都是真正掛鉤的真正頂級功能,它將真實的環境變量和真實的配置文件傳遞到一起。但不要擔心這個開始。首先,當你爲較小的函數編寫單個測試並創建測試嘲笑,假貨和存根將成爲你的第二天性時,你將開始撿起技巧。換另一種說法:即使你不能完全弄清楚如何測試這個函數調用,你仍然有很高的信心,它所調用的所有東西都是完美的。另外,您會注意到測試驅動開發強制您使API更加清晰和靈活。例如:在抽象的某個對象上測試對open()方法進行調用的方法比測試通過它的字符串上的os.open調用要容易得多。 open方法靈活;它可以是僞造的,它可以以不同的方式實現,但是一個字符串是一個字符串,並且os.open不會讓你有任何方法來捕獲它所調用的方法。

您還可以構建測試工具,使重複任務變得輕鬆。例如,twisted提供了用於創建用於測試的臨時文件的工具built right into its testing tool。使用自己的測試庫來測試工具或大型項目具有這樣的功能並不罕見。

2

當我在我的代碼中觸摸文件時,我傾向於嘲笑文件的實際讀寫......所以我可以在測試中給我的類確切的內容,然後斷言測試正在寫回我期望的內容。

我已經在Java中完成了這項工作,並且我認爲它在Python中非常簡單......但它可能需要以這樣的方式設計您的類/函數,以便輕鬆地嘲笑實際文件的使用。

對於這一點,你可以嘗試傳入流,然後只是傳遞中不會寫入文件,或有不實際的一個功能簡單的字符串輸入/輸出流「寫這個字符串到一個文件」或「從文件中讀取此字符串」,然後在測試中替換該函數。

1

我認爲你是在正確的軌道上。取決於你需要做什麼chroot可能會幫助你爲你的scrpits設置一個「看起來」真實但不是的環境。

如果不工作,那麼你可以寫你的腳本採取了「根」路徑作爲參數。

在生產運行中,根路徑只是/。要進行測試,請在/ tmp/test下創建一個影子環境,然後使用根路徑/ tmp/test運行腳本。

7

您有兩個級別的測試。

  1. 過濾和修改內容。這些是「低級」操作,並不真正需要物理文件I/O。這些是測試,決策,替代品等。應用程序的「邏輯」。

  2. 文件系統操作。創建,複製,重命名,刪除,備份。對不起,但那些是適當的文件系統操作 - 很好 - 需要適當的文件系統進行測試。

對於這種測試,我們經常使用「模擬」對象。您可以設計一個體現各種文件系統操作的「FileSystemOperations」類。你測試這個以確保它能夠進行基本的讀取,寫入,複製,重命名等操作。這裏沒有真正的邏輯。只是調用文件系統操作的方法。

然後,您可以創建一個MockFileSystem,它可以虛擬出各種操作。你可以使用這個Mock對象來測試你的其他類。

在某些情況下,您的所有文件系統操作都在os模塊中。如果是這樣的話,你可以用你實際使用的模擬版本的操作來創建一個MockOS模塊。

將您的MockOS模塊放在PYTHONPATH上,您可以隱藏真實的OS模塊。

進行生產作業您使用經過嚴格測試的「邏輯學」類加你FileSystemOperations類(或真正的OS模塊。)

1

,使其運行chroot監牢中你可能要設置的測試,所以即使路徑和文件位置在代碼中被硬編碼了,但你有測試需要的所有環境[這不是一個好習慣,但有時候從其他位置獲取文件位置...],然後通過退出代碼檢查結果。

3

對於稍後想要測試寫入文件的代碼是否正常工作的讀者,以下是一個「fake_open」,用於修補使用StringIO的模塊的打開內置。 fake_open返回一個打開文件的字典,可以在單元測試或doctest中檢查,所有這些都不需要真正的文件系統。

def fake_open(module): 
    """Patch module's `open` builtin so that it returns StringIOs instead of 
    creating real files, which is useful for testing. Returns a dict that maps 
    opened file names to StringIO objects.""" 
    from contextlib import closing 
    from StringIO import StringIO 
    streams = {} 
    def fakeopen(filename,mode): 
     stream = StringIO() 
     stream.close = lambda: None 
     streams[filename] = stream 
     return closing(stream) 
    module.open = fakeopen 
    return streams