Как создать IComparer для теста Nunit CollectionAssert? - PullRequest
9 голосов
/ 24 августа 2011

Я хочу создать следующий тест в NUnit для следующего сценария: мы хотим протестировать созданный новый метод расчета, который дает результаты, аналогичные результатам старой системы.Приемлемая разница (или, скорее, переопределение равенства) между всеми значениями была определена как

 abs(old_val - new_val) < 0.0001

. Я знаю, что могу пройтись по каждому значению из нового списка и сравнить со значениями из старого списка и проверитьвышеуказанное условие.

Как этого добиться, используя метод CollectionAssert.AreEqual Nunit (или какой-нибудь метод CollectionAssert)?

Ответы [ 4 ]

8 голосов
/ 06 октября 2014

Текущие ответы устарели.Начиная с 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));
}
5 голосов
/ 24 августа 2011

Ну, есть метод из NUnit Framework, который позволяет мне проверять допуски для коллекций. См. Равное ограничение . Один использует методы расширения 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
 }
0 голосов
/ 24 августа 2011

Вы спросили, как выполнить желаемый тест, используя метод 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.");
0 голосов
/ 24 августа 2011

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));
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...