Подтвердить что ты не робот

Как я могу расширить класс NUnit Assert, добавив новую статическую перегрузку для AreEqual?

В настоящее время я разрабатываю оболочку С# P/invoke для DLL, которая является частью моего продукта. У меня нет опыта работы с С#, и это первый значительный код С#, который я сделал. Я остро осознаю, что мне не хватает знаний о тонкости и идиомах языка.

Мой вопрос касается модульных тестов, которые я пишу, для которых я использую 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.

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

4b9b3361

Ответ 1

С момента введения в 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 с использованием указанного допуска и не удастся, если какой-либо из них недостаточно закрыт.

Ответ 2

Я думаю, что то, что я сделал бы, просто определит функцию где-нибудь в тестовой проводке

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

который выполняет сравнение и возвращает true или false соответствующим образом. В своем тесте вы просто пишете:

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

Ответ 3

"Лучше" всегда дело вкуса. В этом случае я бы сказал "да". Вы должны сделать свое утверждение, не подклассифицируя nunit assert. Nunit уже имеет несколько классов Assert с различными конкретными утверждениями. Как CollectionAssert. В противном случае ваш метод в порядке.

Ответ 4

Мне нужно было создать пользовательское утверждение, в вашем случае была альтернатива, предоставляемая инфраструктурой. Однако это не сработало, когда я хотел иметь полностью настраиваемый аргумент. Я решил это, добавив новый вызов статического класса в 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);
     }
}

Тогда в тесте

[Test]
public void BarTest()
{
    // Arrange
    ... 

    // Act
    ...

    // Assert
    FooAssert.CountEquals(1, fooConsumer);
}

Я знаю, что я немного опаздываю на вечеринку, это может быть полезно для кого-то