2009-08-19 37 views
6

我想了解國家基礎/交互測試的定義(讀福勒的東西,等等)。我發現我開始基於狀態,但一直在做更多的交互,我對如何測試某些東西感到困惑。國家/互動測試和混亂的混合(或濫用)他們

我在MVC控制器和行動電話服務拒絕包:

public ActionResult Deny(int id) 
{ 
    service.DenyPackage(id); 

    return RedirectToAction("List"); 
} 

這似乎清晰。提供模擬服務,驗證它是否正確調用,完成。

現在,我有一個觀點,即讓用戶的證書與包關聯的動作:

public ActionResult Upload(int id) 
{ 
    var package = packageRepository.GetPackage(id); 
    var certificates = certificateRepository.GetAllCertificates(); 

    var view = new PackageUploadViewModel(package, certificates); 

    return View(view); 
} 

這一次我有點難倒。我正在做Spec樣式測試(可能不正確),所以爲了測試這個方法我有一個類,然後是兩個測試:驗證包調用庫被調用,驗證證書庫被調用。我其實想要第三個測試來驗證構造函數被調用,但不知道該怎麼做!我得到的印象是完全錯誤的。

因此對於基於狀態的測試中,我將通過在ID,然後測試的ActionResult的看法。好的,這是有道理的。但是我不會對PackageUploadViewModel構造函數進行測試嗎?因此,如果我對構造函數進行了測試,那麼我的一部分只是想驗證我是否調用構造函數,並且返回的操作符合構造函數返回的內容。

現在,我可以想到的另一個選項是我有一個PackageUploadViewModelBuilder(或者同樣愚蠢地命名的)依賴於這兩個存儲庫,然後我只是將該ID傳遞給CreateViewModel方法或其他東西。然後,我可以嘲笑這個對象,驗證一切,並開心。但是......好吧......看起來很奢侈。我正在做一些簡單的事情......並不簡單。另外,controller.action(id)返回builder.create(id)好像無故添加一個圖層(控制器負責構建視圖模型..對吧?)

我不知道...我在想更多基於狀態的測試是必要的,但我怕如果我開始測試的返回值那麼如果A法可以得到所謂的在8個不同的上下文中,我將有一個測試爆炸了大量的重複。我一直在使用基於交互測試,通過一些這些上下文方法B,使所有我需要做的就是驗證方法A調用方法B和我有方法B測試,因此方法A可以只相信那些上下文處理。所以基於交互的測試正在構建這種測試層次結構,但基於狀態的測試將會使測試層次更加平滑。

我不知道如果作出任何意義。

哇,這是長...

回答

5

我覺得羅伊Osherove最近挖苦,作爲一個經驗法則,你的測試應該是95%的狀態爲基礎,5%爲基礎的互動。我同意。

最重要的是你的API做你想做的事,是你需要測試的。如果你測試它如何實現它所需要做的機制,你很可能與Overspecified測試,這會咬你的時候還可維護性結束。

在大多數情況下,您可以設計您的API,使基於狀態的測試成爲自然選擇,因爲這樣做更容易。

檢查您的上傳示例:調用GetPackage和GetAllCertificates是否有關係?這真的是Upload方法的預期結果嗎?

我猜不是。我的猜測是,上傳方法的目的 - 這是存在的理由 - 是填充並提供正確的視圖。

因此基於狀態的測試將檢查返回的ViewResult及其ViewModel並驗證它是否具有所有正確的值。

當然,由於代碼現在正確,您將需要爲packageRepository和certificateRepository提供Test Doubles,因爲否則將拋出異常,但是看起來它本身並不重要,因爲存儲庫方法本身調用。

如果您使用Stub而不是Mock作爲存儲庫,那麼測試不再與內部實現細節相關聯。如果稍後決定更改Upload方法的實現以使用包(或任何其他)的緩存實例,則存根將不會被調用,但這沒關係,因爲它無關重要 - 重要的是返回的View包含預期的數據。

即使所有返回的數據都應該如此,這比測試中斷更可取。有趣的是,您的拒絕示例看起來像是一個基於交互的測試仍然有效的主要示例,因爲它只是通過檢查間接輸出來驗證該方法是否執行了正確的操作(DenyPackage方法返回void)。

所有這一切,以及更多,在優秀的書籍xUnit Test Patterns中有很好的解釋。

+0

耶啓發式,拒絕的例子是超級清楚,我應該測試的相互作用。上傳一個是讓我困惑的東西。我在xUnit模式(它顯然很龐大,我害怕我會買它並且沒有閱讀它)的圍欄上,但推薦可能是值得的。有一件事,這可能只是一個細節,但爲了測試上傳一個(這讓我意識到Action是一個可怕的名字......重構時間),我可以(a)手動創建測試視圖,並驗證兩個視圖是否相等,或者(b)測試視圖上的每個屬性等於它應該是什麼。優先? – anonymous 2009-08-19 17:04:34

+0

@eyston:Roy Osherove的着作「單元測試的藝術」是一個很好的選擇,如果你害怕另一個人現在太大了一口 - 但你仍然應該計劃在晚些時候閱讀它。 – 2009-08-19 17:47:58

+0

@eyston:不管你是決定簡單地比較兩個視圖還是所有的屬性,你通常都會做一個邏輯斷言。如果你可以簡單地比較兩個複雜對象,那麼這很容易,但只有當類以正確的方式覆蓋Equals時纔有可能。無論您是否想要,都應根據您希望如何對API進行建模來做出決定。換句話說:不要僅僅爲了測試而覆蓋Equals,但是如果您已經以所需的方式覆蓋了Equals,那麼您絕對可以使用它來做出斷言。 – 2009-08-19 17:51:44

1

問的問題是「如果這段代碼起作用了,我怎麼知道?」這可能意味着要測試一些互動或某種狀態,這取決於什麼是重要的。

在您的第一個測試中,Deny會改變目標課程以外的世界。它需要服務的協作,所以測試交互是有意義的。在你的第二個測試中,你正在對鄰居進行查詢(不改變目標類以外的任何東西),所以對它們進行剔除更有意義。

這就是爲什麼我們有「存根查詢,模擬操作」的http://www.mockobjects.com/book