2011-03-02 70 views
6

我只是在玩.NET 4.0的代碼合同,並且必須丟失一些明顯的東西,因爲它們不像我期望的那樣行事。單元測試代碼合同

我一直使用一個簡單的if ... then .. throw語句來在函數的開始處執行任何驗證。

if (hours < 0 || hours > 8) 
    throw new ArgumentOutOfRangeException("hours", "Hours must be between 0 and 8"); 

我已經簡單地更換這與

Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8"); 

,但它似乎永遠不會扔在我的單元測試的問題。

public static DurationUnit HoursAsDuration(int hours) 
    { 
     Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8"); 

     switch (hours) 
     { 
      case 1: 
      case 2: 
       return DurationUnit.Quarter; 
      case 3: 
      case 4: 
       return DurationUnit.Half; 
      case 5: 
      case 6: 
       return DurationUnit.ThreeQuarter; 
      case 7: 
      case 8: 
       return DurationUnit.Full; 
      default: 
       return DurationUnit.None; 
     } 
    } 

    [Test] 
    public void CanConvertToDuration() 
    { 
     Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(0)); 
     Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(1)); 
     Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(2)); 
     Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(3)); 
     Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(4)); 
     Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(5)); 
     Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(6)); 
     Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(7)); 
     Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(8)); 

     //Would expect this to cause an issue 
     Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(9)); 
    } 

該測試返回true,但我會預期代碼合同停止進入switch語句的「9」的值。這是預期的行爲?

回答

1

如果您的函數的規範使用英文表示,它接受hours的任何值,並在hours不在0..8範圍內時引發異常,則其合同(以代碼合同語言表示)不是它需要hours在0和8之間。正確的翻譯是函數不需要任何東西,並且它確保如果hours在錯誤的範圍內,則引發異常,並且確保如果hours處於正確的範圍,正確的計算完成。

我希望有一種方法可以在代碼合同中表達這些東西,但我不熟悉這種契約語言,只有另一種。不過,哲學是一樣的:如果你想把支票作爲生產版本的一部分,那麼支票的條件不是先決條件。另一方面,合同可能(應該)表示支票已經發出,並且每個案件都得到了適當的處理。

+0

感謝帕斯卡爾,它確實清除了一些東西。我認爲代碼合同可以取代所有參數檢查,但如果我希望他們在生產版本中,他們仍然需要保留。 – fluent 2011-03-03 09:08:34

+0

更新:下面的Porges指出我正確的方向,編輯項目設置以啓用生產版本中的合同。 – fluent 2011-03-03 09:18:30

-1

我認爲你需要在你的小時參數周圍交換測試。

你應該定義可以通過的規則。

,所以我認爲這會爲你工作...

Contract.Requires<ArgumentOutOfRangeException>(hours < 0 && hours > 8, "Hours must be between 0 and 8"); 
+0

謝謝,你在我的文章中發現了一個有點誤導的錯誤。原來的if ... then .. throw是錯誤的,現在我已經糾正了。但問題依然存在。 – fluent 2011-03-02 10:27:45

+4

-1:這沒有任何意義。你基本上認爲你需要同時小於零和大於8。 – Virtlink 2012-03-22 12:54:11

0

好吧,我現在有代碼啓用拋出預期的錯誤「執行運行時檢查合同」,在Visual Studio中的項目屬性中選擇。

這是否意味着當發佈到生產時代碼合同被有效忽略?

我明顯地誤解了代碼合約應該如何使用,所以如果有人可以指向我的最佳實踐文章的方向,我會很感激。

在MSDN頁面狀態:

「合同類的大多數方法是有條件編譯;也就是說,編譯器生成這些方法的調用,只有當你定義一個特殊的符號,合同FULL,使用中的#define指令CONTRACTS FULL可以讓你在不使用#ifdef指令的情況下在你的代碼中編寫契約;你可以產生不同的版本,有些版本有契約,有些則沒有。「

這是否意味着我仍然會更好地使用if .. then .. throw ..對於任何面向公衆的?參數驗證檢查確實有助於減少數據損壞,因爲它會盡早標記故障點。

+0

對於答案中的所有問題,我會說「是」,我會擴展一點點,但StackOverflow註釋有點限制,所以我寫了另一個答案。 – 2011-03-02 11:42:09

+1

rggardner:項目屬性中有很多選項:)您可以爲發佈構建啓用運行時實施,或者根據需要禁用它。這取決於你想要對合同做什麼。你也可以只在面向公衆的方法,如 – porges 2011-03-03 00:17:41

+0

感謝Porges,非常有用的知道。我現在需要做的是將正確的設置工作到我的構建文件中。 – fluent 2011-03-03 09:17:13