[英]How do I create an IComparer for a Nunit CollectionAssert test?
我希望在NUnit中為以下場景創建以下測試:我們希望測試正在創建的新計算方法產生類似於舊系統的結果。 所有值之間的可接受差異(或者更確切地說是重新定義)已被定義為
abs(old_val - new_val) < 0.0001
我知道我可以循環遍歷新列表中的每個值,並與舊列表中的值進行比較並測試上述條件。
如何使用Nunit的CollectionAssert.AreEqual
方法(或一些CollectionAssert
方法)實現這一目標?
目前的答案已經過時。 從NUnit 2.5開始, CollectionAssert.AreEqual
重載了一個System.Collections.IComparer
。
這是一個最小的實現:
public class Comparer : System.Collections.IComparer
{
private readonly double _epsilon;
public Comparer(double epsilon)
{
_epsilon = epsilon;
}
public int Compare(object x, object y)
{
var a = (double)x;
var b = (double)y;
double delta = System.Math.Abs(a - b);
if (delta < _epsilon)
{
return 0;
}
return a.CompareTo(b);
}
}
[NUnit.Framework.Test]
public void MyTest()
{
var a = ...
var b = ...
NUnit.Framework.CollectionAssert.AreEqual(a, b, new Comparer(0.0001));
}
那么NUnit框架中的方法允許我對集合進行容差檢查。 請參閱Equal Constraint 。 一個使用AsCollection
和Within
擴展方法。 在這方面,盡管我對這一陳述的含義並非100%肯定
如果要將要比較的數組視為簡單集合,請使用AsCollection修飾符,這將導致逐個元素地進行比較,而不考慮數組的等級或維度。
[Test]
//[ExpectedException()]
public void CheckLists_FailsAt0()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result1 = new[] { -0.0004, 0.43520, 1.3454, 345345.0980 };
Assert.That(result1, Is.EqualTo(expected).AsCollection.Within(0.0001), "fail at [0]"); // fail on [0]
}
[Test]
//[ExpectedException()]
public void CheckLists_FailAt1()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result1a = new[] { 0.0001000000 , 0.4348245000 , 1.3450234000 , 345345.0975980000 };
Assert.That(result1a, Is.EqualTo(expected).AsCollection.Within(0.0001), "fail at [1]"); // fail on [3]
}
[Test]
public void CheckLists_AllPass_ForNegativeDiff_of_1over10001()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result2 = new[] { 0.00009900 , 0.43532350 , 1.34552240 , 345345.09809700 };
Assert.That(result2, Is.EqualTo(expected).AsCollection.Within(0.0001)); // pass
}
[Test]
public void CheckLists_StillPass_ForPositiveDiff_of_1over10001()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result3 = new[] { 0.00010100 , 0.43532550 , 1.34552440 , 345345.09809900 };
Assert.That(result3, Is.EqualTo(expected).AsCollection.Within(0.0001)); // pass
}
NUnit不定義任何委托對象或接口來對列表執行自定義檢查,並確定預期結果是否有效。
但我認為最好也是最簡單的選擇是編寫一個實現檢查的小型靜態方法:
private const float MIN_ACCEPT_VALUE = 0.0001f;
public static void IsAcceptableDifference(IList collection, IList oldCollection)
{
if (collection == null)
throw new Exception("Source collection is null");
if (oldCollection == null)
throw new Exception("Old collection is null");
if (collection.Count != oldCollection.Count)
throw new Exception("Different lenghts");
for (int i = 0; i < collection.Count; i++)
{
float newValue = (float)collection[i];
float oldValue = (float)oldCollection[i];
float difference = Math.Abs(oldValue - newValue);
if (difference < MIN_ACCEPT_VALUE)
{
throw new Exception(
string.Format(
"Found a difference of {0} at index {1}",
difference,
i));
}
}
}
您已經問過如何使用CollectionAssert方法實現所需的測試,而無需遍歷列表。 我確信這是顯而易見的,但循環正是這樣一種方法會做的......
對您的確切問題的簡短回答是您不能使用CollectionAssert方法來執行您想要的操作。 但是,如果您真正想要的是一種比較浮點數列表並斷言它們相等的簡單方法,那么請繼續閱讀。
方法Assert.AreEqual( double expected, double actual, double tolerance )
您無需自己編寫單個項目斷言。 使用LINQ,您可以執行以下操作:
double delta = 0.0001;
IEnumerable<double> expectedValues;
IEnumerable<double> actualValues;
// code code code
foreach (var pair in expectedValues.Zip(actualValues, Tuple.Create))
{
Assert.AreEqual(pair.Item1, pair.Item2, delta, "Collections differ.");
}
如果你想變得更加漂亮,你可以把它拉成一個自己的方法,捕獲AssertionException,按摩它並重新拋出它以獲得更清晰的界面。
如果您不關心哪些項目有所不同:
var areEqual = expectedValues
.Zip(actualValues, Tuple.Create)
.Select(tup => Math.Abs(tup.Item1 - tup.Item2) < delta)
.All(b => b);
Assert.IsTrue(areEqual, "Collections differ.");
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.