2015-04-07 48 views
5

看起來像使用它們作爲一種方法來確定被測試的方法是否適當執行會適得其反,因爲這會導致脆弱的測試。換句話說,你將測試與實現聯繫起來。所以如果你以後想改變實現,你也將不得不改變測試。我在問這個問題,因爲我接受過每個單元測試都至少使用這些方法中的一種的訓練,我想我可能只是有一個頓悟,這實際上是一個非常糟糕的做法。您應該在單元測試中使用Moq提供的「Verify」和「VerifyAll」方法嗎?

+0

我認爲他們也是不好的做法。正如你所說,它們毫無用處,甚至是無益的。從此沒有任何東西可以從人們獲得,但人們通過自動化來實現。它違背了單元測試的想法,所以除非別人能提供一個很好的理由:不要打擾他們。 –

回答

4

模擬爲基礎的測試

有很多周圍嘲弄的脆性辯論的單元測試,以及他們是否是好事還是壞事。我個人認爲這是你必須在可維護性和穩健性之間進行折衷。您將生產代碼放在unit test pressure以上的地方,使用mock進行隔離測試,越少可能的實現就會通過測試。因此,您可以將您的生產代碼強制轉換爲良好的設計。另一方面,它確實將自己與特定的實現綁定在一起,並增加了維護負擔,因爲一旦實現細節發生變化,就必須更改更多的測試。

的VerifyAll()語法

這主要是口味的問題,但我發現,當你讀一個測試套件,你會期望得到規範的一個好主意VerifyAll()並不打算暴露,即只要看看這些斷言,VerifyAll()根本就沒有意義。 即使當我編寫基於模擬的測試我更喜歡Arrange Act Assert方法與特定的斷言失敗消息。它比全面呼叫VerifyAll()更清晰,更「神奇」。

使用VerifyAll()在每一個測試方法

這是最好矯枉過正和在最壞的情況會導致測試套件的傷害。

  • 作爲一般規則,單元測試應該只測試一件事情。除了正常的斷言之外,系統地調用VerifyAll()也會造成混淆 - 如果測試失敗,則無法確定哪裏出錯。

  • 就可讀性而言,您只是將噪聲添加到每個測試中。通過閱讀測試方法追溯到真正意義上的東西是非常困難的。

  • 您通常希望選擇將模擬應用中的設計壓力應用到哪裏,而不是盲目地將其應用於任何地方,因爲它有維護價格。

所以,如果你真的要使用VerifyAll(),更好地IMO編寫單獨的測試吧。

0

首選的方法是使用AAA。但對於具有void返回類型的外部依賴項(可以說void WriteData(Data data)),Verify可以是有用的(或者安裝程序,然後是VerifyAll)。

10

首先,要明白Verify - 家庭的方法有一個原因是很重要的 - 它們允許你測試你的系統不可觀測行爲。我的意思是什麼?考慮應用程序生成和發送報告的簡單示例。您的最終組件很可能看起來像這樣:

public void SendReport(DateTime reportDate, ReportType reportType) 
{ 
    var report = generator.GenerateReport(reportDate, reportType); 
    var reportAsPlainText = converter.ConvertReportToText(report); 
    reportSender.SendEmailToSubscribers(body: reportAsPlainText); 
} 

您如何測試此方法?它不會返回任何內容,因此您無法檢查值。它不會改變系統的狀態(如翻轉某個標誌),因此你也不能檢查。 SendReport被調用的唯一可見結果是報告通過SendEmailToSubscribers調用發送。這是SendReport方法的主要職責 - 這就是單元測試應該驗證的內容。

當然,您的單元測試不應該也不會檢查某些電子郵件是發送還是發送。你將驗證模擬reportSender。這是您使用Verify方法的地方。檢查一些模擬電話實際發生了什麼。

最後一點,羅伊Osherove在他的書中Art Of Unit Testing (2nd edition)單元測試分爲三個類別,具體取決於什麼可以檢查:方法

  • 返回值(簡單,普通)
  • 變化在系統狀態(簡單,罕見)
  • 呼叫到外部元件(複雜峯,罕見)

最後一類是wher如果你使用mocks和Verify方法。對於其他兩個,存根已足夠(Setup方法)。

當你的代碼設計正確時,這樣的測試(最後一個類別)在你的代碼庫中佔少數,在5%-10%範圍內(根據我的觀察,來自Roy的書中的數字)。


:不可觀,如呼叫者不能輕易確認來電後究竟happend。