2011-11-17 90 views
12

我目前正在開發一個C#P/invoke包裝到屬於我產品一部分的DLL。我沒有使用C#的經驗,這是我所做的第一個重要的C#編碼。我非常清楚,我對語言的細節和習慣用法缺乏瞭解。如何通過爲AreEqual添加新的靜態過載來擴展NUnit Assert類?

我的問題涉及到我正在使用NUnit編寫的單元測試。我需要比較double[]變量的值。如果我使用Assert.AreEqual(...)來做到這一點,那麼將比較這些值的完全相等。不過,我想比較一下寬容。標量實數值有AreEqual()過載,允許參數爲delta。但是,我一直無法找到數組的等價物。我錯過了明顯的東西嗎?

在我已經用下面的代碼解決了這個問題的時刻:

class Assert : NUnit.Framework.Assert 
{ 
    public static void AreEqual(double[] expected, double[] actual, double delta) 
    { 
     AreEqual(expected.Length, actual.Length); 
     for (int i = 0; i < expected.Length; i++) 
     { 
      AreEqual(expected[i], actual[i], delta); 
     } 
    } 
} 

雖然這似乎是工作,我不知道是否有可用的清潔的解決方案。特別是我擔心的是,爲我的派生類使用相同的名稱,不僅風格不佳,而且會導致未預料到的問題。

我想要使用擴展方法,但我知道它們只有在有擴展類的實例時纔可行。當然,我只會在Assert課上調用靜態方法。

對不起,如果這看起來有點模糊,但我的直覺告訴我,我沒有這樣做最好的方式,我想知道如何做到這一點。

+1

你嘗試[擴展方法( http://msdn.microsoft.com/en-us/library/bb383977.aspx)? –

+5

@Ofer澤裏格柯而我給你的+1我記得擴展方法,而定義的靜態,只能在實例工作。 – dowhilefor

+0

那麼作爲現在看來,是無法做到的(除非你實現包裝類,大量的艱苦和醜陋的工作)。參見[此](http://stackoverflow.com/questions/249222/can-i-add-extension-methods-to-an-existing-static-class/435617#435617)和[此](HTTP:// madprops.org/blog/static-extension-methods/)。 –

回答

7

由於引進NUnit的流利斷言語法中,Within()方法已可用於這一目的:

double actualValue = 1.989; 
double expectedValue = 1.9890; 
Assert.That(actualValue, Is.EqualTo(expectedValue).Within(0.00001)); 
Assert.That(actualValue, Is.EqualTo(expectedValue).Within(1).Ulps); 
Assert.That(actualValue, Is.EqualTo(expectedValue).Within(0.1).Percent); 

對於集合的Is.EqualTo()的默認行爲是集合的成員單獨比較,有這些個人比較正在修改Within()。因此,你可以比較的雙打兩個數組,像這樣:

var actualDoubles = new double[] {1.0/3.0, 0.7, 9.981}; 
var expectedDoubles = new double[] { 1.1/3.3, 0.7, 9.9810}; 
Assert.That(actualDoubles, Is.EqualTo(expectedDoubles).Within(0.00001)); 
Assert.That(actualDoubles, Is.EqualTo(expectedDoubles).Within(1).Ulps); 
Assert.That(actualDoubles, Is.EqualTo(expectedDoubles).Within(0.1).Percent); 

這會的actualDoubles每個元素expectedDoubles使用規定的公差比較相應的元素,如果有任何不足夠接近將失敗。

+0

非常感謝。看起來這是我希望解決問題的方式。我很感謝你在這裏的時間。非常感謝。作爲個人品味的事情,我發現這些流暢的界面有點不透明。一旦你把它寫下來,這是有道理的,但你必須破解代碼才能第一次寫! –

+1

我認爲這種流暢的接口技巧是'點驅動開發'。如果您使用的是像Visual Studio這樣的IDE,您只需要知道鏈中的第一個「鏈接」,例如'是',那麼你可以擊中'.',智能感知系統會向你顯示你'下一步'的所有選項。我通過這種方式瞭解了像Within()這樣的許多功能,而不是通過閱讀NUnit文檔。 – Peter

2

我想我會做的只是在你的測試工具

public static bool AreEqual(double[], double[], double delta)

,做比較,並適當地返回真或假的某處定義一個函數。在您的測試,你只要寫:

Assert.IsTrue(AreEqual(expected, result, delta)) ; 
+0

謝謝你。這當然是一個好主意。對我來說,缺點是,我發現,當我試圖實現這一點,我不得不重新實現,當你調用AreEqual與真正的標量輸入,附帶免費的'delta'比較。所以@dowhilefor的回答似乎更適合我的需求。謝謝關心! –

2

「更好」始終是一個品味的問題。在這種情況下,我會說是的。你應該建立你自己的斷言,而不需要繼承nunit斷言。 Nunit已經擁有多個具有不同特定斷言的Assert類。像CollectionAssert。否則你的方法很好。

+0

感謝您的支持。我沒有發現其他'XXXAssert'類。於是我添加了一個'ArrayAssert'類,並將代碼移到了那裏。現在感覺很自然,我的不愉快的感覺已經消退。 –

2

我有需要創建自定義斷言,在你的情況下有框架提供了一個替代。但是,當我想要一個完全自定義的斷言時,這不起作用。我通過向nunit添加一個新的靜態類來解決這個問題。

public static class FooAssert 
{ 
    public static void CountEquals(int expected, FooConsumer consumer) 
    { 
     int actualCount = 0; 
     while (consumer.ConsumeItem() != null) 
      actualCount++; 

     NUnit.Framework.Assert.AreEqual(expected, actualCount); 
    } 
} 
在測試

​​

我知道我是有點晚了黨

然後,它可能仍然是有用的人