2010-04-20 11 views
6

我一直在嘗試開始單元測試,同時在一個小小的cli程序上工作。我應該如何重寫我的數據庫執行/提交以使其適合單元測試?

我的程序基本解析命令行參數和選項,並決定調用哪個函數。每個函數都在數據庫上執行一些操作。

所以,舉例來說,我可能有一個創建功能:

def create(self, opts, args): 
    #I've left out the error handling. 
    strtime = datetime.datetime.now().strftime("%D %H:%M") 
    vals = (strtime, opts.message, opts.keywords, False) 
    self.execute("insert into mytable values (?, ?, ?, ?)", vals) 
    self.commit() 

如果我的測試情況下調用這個函數,然後執行選擇SQL檢查該行已輸入?這聽起來很合理,但也使測試更難以維護。你會重寫函數來返回一些東西並檢查返回值嗎?

感謝

+0

我認爲單元測試是兩個單詞。書中使用了 – 2010-04-20 02:33:02

回答

8

Alex的答案涵蓋了依賴注入的方法。另一個是要考慮你的方法。就目前而言,它有兩個階段:構建一條SQL語句,並執行SQL語句。你不想測試第二階段:你沒有編寫SQL引擎或數據庫,你可以認爲它們工作正常。階段1是你的工作:構建一個SQL語句。所以,你可以重新組織代碼,以便您可以測試只是階段1:

def create_sql(self, opts, args): 
    #I've left out the error handling. 
    strtime = datetime.datetime.now().strftime("%D %H:%M") 
    vals = (strtime, opts.message, opts.keywords, False) 
    return "insert into mytable values (?, ?, ?, ?)", vals 

def create(self, opts, args): 
    self.execute(*self.create_sql(opts, args)) 
    self.commit() 

create_sql功能是第1階段,而現在它的方式,可以讓你直接寫測試反對錶示:它需要值並返回值,因此您可以編寫涵蓋其功能的單元測試。 create函數本身現在更簡單了,不需要進行如此詳盡的測試:您可以通過一些測試來證明它確實能夠正確執行SQL,但是您不必覆蓋create中的所有邊界案例。

BTW:This video from Pycon (Tests and Testability)可能是有趣的。

6

我肯定會重構便於測試此方法 - 例如,依賴注入可以幫助:

def create(self, opts, args, strtime=None, exec_and_commit=None): 
    #I've left out the error handling. 
    if strtime is None: 
     strtime = datetime.datetime.now().strftime("%D %H:%M") 
    vals = (strtime, opts.message, opts.keywords, False) 
    if exec_and_commit is None: 
     exec_and_commit = self.execute_and_commit 
    exec_and_commit("insert into mytable values (?, ?, ?, ?)", vals) 

這當然假設你有一個execute_and_commit方法調用execute然後commit方法。

這樣,測試代碼可以爲strtime注入一個已知值,並將其自己的可調用注入爲exec_and_commit以驗證它是否使用期望的參數進行調用。

0

不熟悉Python語法,但如果你是新的單元測試,開始最簡單的方法可以提取您在命令行參數傳遞的方法,並取回SQL命令。在這種方法中,您可以測試代碼中真正邏輯所在的部分。 傳遞不同類型的參數,並根據sql命令的結果檢查結果。一旦開始獲得單元測試的樂趣,您可以學習一些關於模擬和依賴注入的知識,以測試您是否正確調用了更新db的函數。

希望你更熟悉Java C#語法比我用Python語法:)

public string GetSqlCommand(string[] commandLineArgs) 
{ 
    //do your parsing here 
    return sqlCommand; 
} 
[Test] 
public void emptyArgs_returnsEmptySqlCommand() 
{ 
    string expectedSqlCommand=""; 
    assert.AreEqual(expectedSqlCommand, GetSqlCommand(new string[]) 
} 
3

一般來說,你喜歡的單元測試到位重構之前,以確保沒有重大更改制成。然而爲了啓用可測試性,可能還需要進行一些重構...一個不幸的悖論,一個曾經咬過我的悖論。

這就是說,有一些小的重構可以安全地完成,而不會改變行爲。重命名和提取是兩個。

我建議你看看Michael Feathers的書,使用遺留代碼。它側重於重構可測試性的代碼。這些示例是用Java編寫的,但這些概念同樣適用於Python。

+0

和C++代碼 – Gutzofter 2010-04-20 05:40:41

相關問題