2010-09-23 23 views
1

說我有以下業務邏輯:如何測試的對象得到更新使用假倉庫

foreach (var item in repository.GetAll()) 
    { 
     if (SomeConditition) 
     { 
      item.Status = Status.Completed; 
      repository.Update(item); 
     } 
    } 

現在,我寫了下面的單元測試:

public void Test() 
    { 
     var repository = new FakeRepository(); 
     repository.Add(new Item()); 

     RunBusinessLogic(repository); 

     Assert.AreEqual(Status.Completed, repository[0].Status); 
    } 

FakeRepository是一個列表來實現,而GetAll()只是返回列表。

雖然我可以測試使用此方法涉及的大部分邏輯,但我無法驗證是否已記住在業務代碼中調用repository.Update()。由於FakeRepository.GetAll()返回實際對象,因此在調用Update()之前,存儲庫對象將已被業務代碼修改。實際上,FakeRepository.Update()什麼也不做。

我知道我可以使用FakeRepository.Update記錄它已被調用,並在測試中斷言。但是,如果我忘記調用更新,我不能相信要記住更新,對嗎?如果省略了更新調用,我寧願測試簡單失敗。

任何想法?

回答

3

模擬框架在這裏可能很有用,因爲它允許您驗證哪些方法實際被調用。僅舉幾例:

下面是這三個流行的框架之間的nice comparison

+0

正如我上面提到的,我還可以用我的假倉庫,以驗證更新是否已被調用。但是當我忘記在業務代碼中調用Update時,即使我不這樣做,我也希望測試失敗。如果我的假存儲庫更實際並且返回副本而不是來自GetAll的真實存儲庫對象引用,那麼測試會正常失敗。因此,使用內存數據庫作爲存儲庫將是解決我的問題的一種方法。但我想知道是否有更簡單的解決方案。 – 2010-09-24 11:43:04

1

我知道我可以使用 FakeRepository.Update來記錄 它被調用,一個斷言,在 測試。但是如果我忘記打電話 更新,我不能信任 請記住要斷言更新, 對不對?如果省略更新呼叫 ,我寧願測試 簡單地失敗。

當您注意到您未測試該更新被調用,或者您注意到沒有調用更新時,那就是當您編寫測試時更新被調用。並不是說知識庫中的項目已完成,但更新被調用(這是一個不同的測試)。你已經決定,更新被調用對你來說很重要,所以你需要測試它。完成這個任務的方式與您概述的一樣 - 在您的FakeRepository中記錄要更新的調用,並對其進行測試。

+0

是的,我認爲這一定是必須的。但是這個問題是我必須等到更新丟失的bug表面,直到我知道我必須測試並修復它爲止。如果我的假存儲庫更實際一些,並且沒有從GetAll返回真正的存儲庫對象引用,那麼如果忘記Update,我的測試將會失敗。 – 2010-09-24 11:37:48

1

有幾件事情可以在這裏單獨進行單元測試:Repository.getAll()和​​方法,以及評估每個項目或每種項目的完成條件。我不確定我會在這裏使用FakeRepository。

如上所述,另一種選擇是使FakeRepository.update()方法記錄和/或計算更新次數。

但是,如果我忘記打電話更新,我不能信任記得斷言更新,對不對?

正確,但是當您遵循TDD過程時,您將首先通過測試失敗 - 紅色 - 然後編寫代碼使其通過 - 綠色。您將首先編寫斷言,導致測試失敗,然後調用update()方法,使測試通過。

+0

是的,我們可以使用集成測試來測試GetAll和Update,以及單元測試的完成條件。但是,即使我忘記在示例循環中調用Update,它們也可能都是綠色的。換句話說,我從來沒有被告知我需要致電更新。 – 2010-09-24 11:31:43

+0

GetAll()和Update()也可以進行單元測試,我將重新解釋我的答案。 TDD的一個常見隱喻是雙重記錄,因此,它*減少了出錯的概率,你必須做出兩個錯誤,以便它不被檢測到。 – philant 2010-09-24 16:04:24

0

鑑於沒有回答是否已經被接受,那答案是正確的,我可能會建議托爾·霍夫蘭可能會問一個稍微不同的問題(在我的愚見!):

具體來說,Tor的可能詢問如何確保他的單元測試調用Update調用,並且在這種情況下單元測試應該失敗。

如果是這樣的情況下,存在需要被所述兩件事情:

首先,如果這是重要的,考慮添加測試代碼拆機()或適當的方法在單元測試,然而,這有問題,因爲它實際上沒有測試應用程序代碼是否正確 - 可能有應用程序代碼無法調用更新調用。

如果有沒有正確調用Update()的應用程序代碼,並且代碼恰好依賴於它(誰知道爲什麼...也許代碼有一個錯誤,只是碰巧工作,因爲它doesn ),並且開發人員修改這些庫以使某些行爲被更改,以便自動調用Update()或者現在討論的錯誤代碼現在調用它,現在您的單元測試功能發生了變化不要測試,因爲他們總是調用更新。

因此,這導致需要說的第二點 - 單元測試需要測試應用程序代碼的功能。單元測試「不是嚴格正確地使用代碼」並不重要,重要的是單元測試測試代碼本身的結果。換句話說,測試代碼調用Update(),或者測試Update()的副作用是否存在。

重新迭代,並重新回答我有點冗長的答案,不測試測試

+0

你可能是正確的,我問的是一個微妙不同的問題,但是這個問題是:我如何實現一個與數據庫一樣真實的假存儲庫,因爲在更新被調用之前,沒有哪個狀態實際上發生變化? – 2010-12-20 18:31:10

+0

所以你想要系統測試,而不是單元測試? – Arafangion 2010-12-20 23:42:01

0

更好的方法是使用開發魔術假的,所以你可以模擬數據庫中,可以是永久的也一樣,你也可以嘲笑UI

只需添加一個參考DevMagicFake.dll

,你可以代碼如下:

[HttpPost] 
public ActionResult Create(VendorForm vendorForm) 
{ 
    var repoistory = new FakeRepository<VendorForm>(); 
    repoistory.Save(vendorForm); 
    return View("Page", repoistory.GetAll()); 
} 

這將節省VendorForm永久的記憶,你可以找回任何時候,你還可以生成此對象或任何其他對象在模型中,有關開發魔術假的更多信息數據請參閱以下鏈接在CodePlex上:

http://devmagicfake.codeplex.com

感謝

M.Radwan