2016-01-27 26 views
2

我對測試驅動開發相當新穎,我剛開始學習SOLID原則,所以我希望有人能幫助我。在開發TDD範例中的單元測試和方法的背景下,我對理解單一責任原則有一些概念性的困難。例如,假設我希望開發刪除從數據庫 - 一個項目之前,我的代碼看起來會像下面的方法...單一責任原則,測試驅動開發和功能設計

我會用定義測試用例開始:

"Delete_Item_ReturnsTrue": function() { 
    //Setup 
    var ItemToDelete = "NameOfSomeItem"; 
    //Action 
    var BooleanResult = Delete(ItemToDelete); 
    //Assert 
    if (BooleanResult === true) { 
     return true; 
    } else { 
     console.log("Test: Delete_Item_ReturnsTrue() - Failed."); 
     return false; 
    } 
} 

我運行測試,以確保它失敗了,那麼我會制定方法...

function Delete(ItemToDelete) { 
    var Database = ConnectToDatabase(); 
    var Query = BuildQuery(ItemToDelete); 
    var QueryResult = Database.Query(Query); 
    if (QueryResult.error !== true) { 
    //if there's no error then... 
     return true; 
    } else { 
     return false; 
    } 
} 

如果我理解正確的單一職責原則,我原來寫的方法有責任刪除該項目並返回true,如果沒有錯誤。所以,如果我按照SOLID範式的原始方法需要重構看起來像...

function Delete(WhatToDelete, WhereToDeleteItFrom) { 
    WhereToDeleteItFrom.delete(WhatToDelete); 
} 

做設計本身,改變了我的方法從布爾函數void函數所以現在我不能以我測試舊方法的相同方式真正測試新方法。

我想我可以測試拋出的異常,但然後不會使它成爲一個集成測試,而不是單元測試,因爲沒有實際的異常拋出該方法?

我是否設計並實現了一個額外的函數來檢查數據庫以用於我的單元測試?

難道我只是不測試它,因爲它是無效的? TDD的工作原理如何?

我是否傳入模擬存儲庫,然後在狀態發生變化後將其返回?難道這不就是讓我回到原點嗎?

我是否傳入對模擬存儲庫的引用,然後在方法完成後僅對存儲庫進行測試?那不會被認爲是副作用嗎?

回答

2

所以單一責任原則說:當我需要改變一個功能時,他們應該是確切的一個原因。

因此,讓我們看看你的函數:

function Delete(ItemToDelete) { 
    var Database = ConnectToDatabase(); 
    var Query = BuildQuery(ItemToDelete); 
    var QueryResult = Database.Query(Query); 
    if (QueryResult.error !== true) { 
    //if there's no error then... 
     return true; 
    } else { 
     return false; 
    } 
} 
  • 數據庫的變化:ConnectToDatabese()需要改變,而不是這個功能
  • 變化在DB結構:BuildQuery對於()需要改變(也許)
  • ...

於是就先來看看,你的函數看起來不錯。某些地方的命名有點混亂。函數應該以小寫字母開頭。例如「connectToDatabase()」。 connectToDatabase返回一個Object有點令人驚訝。

名稱BuildQuery似乎是錯誤的,因爲BuildQuery(myItem)返回一個查詢,刪除一些東西。

但我永遠不會有這麼長的複雜功能,只有一個測試用例。

你需要編寫更多的測試用例。 對於第一個測試用例,你可以寫這樣的功能:

function Delete(ItemToDelete) { 
    return true 
} 

下一個測試用例可能是「呼叫與該項目ID的buildDeleteQuery功能」。那時你需要考慮如何調用你的db。如果你有一個dbObject,那你可以嘲笑那個Object。

function Delete(ItemToDelete) { 
    buildDeleteQuery(ItemToDelete.id) 
    return true 
} 

現在越來越多的測試用例。請記住,還會有buildDeleteQuery的測試用例。但對於外部函數,你可以模擬buildDeleteQuery。

現在來回答大家的一些問題:

  • 當你第一次寫的測試,然後編寫代碼,你將有可測試的代碼。
  • 該代碼看起來不同,因爲測試應該不復雜。當你想要簡單的測試時,你會自動擁有更小的功能。
  • 是的,你會爲你打電話的每個功能寫一個測試。
  • 也許你會嘲笑對象。如果你不能在沒有包裝函數的情況下測試你的db調用,你將創建一個函數,它允許你測試這個函數。
  • 記住你的測試是你的代碼的文檔。所以儘可能保持簡單。

但最重要的事情是:保持練習!當你開始使用TDD時,需要一些時間。一個好的和有趣的資源是:Uncle Bobs Bowling Kata只需從網站上下載幻燈片,並看看tdd是如何一步一步完成的。