НУнит — Равный(это, то), Истинный(это == то) или То (это, Равно(то))?

#c# #nunit

Вопрос:

Наша домашняя платформа использует универсальный класс DBField<T> , для эмуляции полей сущностей с базами данных , которые несовместимы с Entity Framework (например, Oracle 11 или Sybase).

Мы пытаемся сделать его как можно более прозрачным (опять же, как поля сущностей), чтобы работал следующий код:

     DBField<int?> z_intLength = 2;
    while (z_intLength <= 5)
    {
        z_intLength  ;
    }

    //[...]

    DBField<int?> z_intMaxLength = 10;
    if (z_intLength > z_intMaxLength)
    {
    }
 

Все вышесказанное прекрасно работает. Мы использовали public static implicit operator DBField<T>(T value) и public static implicit operator T(DBField<T> value) , наряду с переопределением == и другими операторами сравнения, а также реализовали IEquatable<DBField<T>> , IComparable , и IComparable<DBField<T>> .

Сейчас мы пытаемся DBField<T> пройти тесты NUnit, в которых мы довольно новички.

Примечательно, что мы пробуем свои силы с различными эквивалентами:

             string z_strComment = "Comment";
            _objOrder2.OrderComment = z_strComment;

            //[...]

            Assert.True("Comment" == _objOrder2.OrderComment);
            Assert.That("Comment", Is.EqualTo(_objOrder2.OrderComment));
            Assert.That(_objOrder2.OrderComment, Is.EqualTo("Comment"));
            Assert.Equals("Comment", _objOrder2.OrderComment);
 

Первые два утверждения проходят, а следующие два терпят неудачу.

  1. По-видимому, существует разница во внутренней работе каждого утверждения. Может кто-нибудь объяснить, что это такое?
  2. Точнее, отладка с точками останова, по-видимому, указывает на эти Assert.That("Comment", Is.EqualTo(_objOrder2.OrderComment)) тесты _objOrder2.OrderComment.Equals("Comment") ; я бы ожидал, что все будет наоборот. Я что-то упускаю?
  3. Я это понимаю True() и Equals() старше, чем That() . Какие из них предпочтительнее в каких ситуациях?

Комментарии:

1. Is.EqualTo и Equals проверяет также тип объекта, а не просто логическое условие, стоящее за ним. Поэтому имеет смысл, что ваше свойство пользовательского объекта не равно System. Строка, так как она другого типа.

Ответ №1:

Здесь играют 2 вещи:

  1. Насколько полезно сообщение об ошибке от NUnit в случае сбоя теста
  2. Какой стиль API NUnit вы используете

 Assert.True("Comment" == _objOrder2.OrderComment)
 

Если этот тест не пройдет, вы получите сообщение типа «Ожидалось верно, было ложно». Бесполезно, так как это не говорит вам, какова была ценность _objOrder2.OrderComment на самом деле.


 Assert.Equals("Comment", _objOrder2.OrderComment);
Assert.That(_objOrder2.OrderComment, Is.EqualTo("Comment"));
 

Эти два варианта эквивалентны, первый использует немного более короткий синтаксис, второй использует более расширяемую модель ограничений (например, вы можете написать свои собственные утверждения Assert.That(x, new MyConstraint(y)) ).

Если тест провалится, вы получите что-то вроде Expected "Comment", was "Actual Value" . Это немного более полезно.


 Assert.That("Comment", Is.EqualTo(_objOrder2.OrderComment));
 

Этот-наоборот. Если это не удастся, вы получите что-то вроде Expected "Actual Value", was "Comment" , что просто неправильно.


Что касается более старого стиля Assert.Equals по сравнению с моделью ограничений Assert.That , это (досадно) зависит от личных предпочтений. Лично я использую Assert.Equals его, потому что мне легче читать, но я буду использовать Assert.That CollectionAssert его при выполнении утверждений в коллекциях, а также при написании собственных утверждений.

Прочитайте комментарий одного из разработчиков NUnit ниже о том, как они обнаружили, что пользователям Assert.That легче понять стиль.

Комментарии:

1. Хороший ответ! Я добавлю, что старшие Assert.Equals привели к большой путанице в отношении надлежащего порядка. Похоже, что ставить ожидаемое значение на первое место естественно только для разработчиков с опытом работы в других системах, которые делают то же самое. Assert.That с фактическим значением в качестве первого аргумента большинству пользователей было легче понять, поскольку он имитирует порядок естественного языка в английском, а также во многих европейских языках. Конечно, большинство людей находят вещи естественными, когда они к ним привыкли. 🙂

2. Assert.That не использует == оператора. Если вы явно тестируете == оператора, я бы ожидал, что вы будете звонить == сами, а не утверждать, что NUnit делает то, что вы ожидаете.

3. Да, в этом очень конкретном случае (и вы бы не делали этого со строками, как это делает ваш вопрос!). Но я бы сильно прокомментировал это и добавил ваше собственное пользовательское сообщение к утверждению.

4. @Jean-DavidLanz На самом деле классические утверждения и утверждения на основе ограничений используют одну и ту же реализацию… они являются просто синтаксисом поверх внутренней реализации. На самом деле, когда были введены утверждения, основанные на ограничениях, все классические утверждения были переписаны так, чтобы они фактически называли модель, основанную на ограничениях. Что касается того, почему он использует expected.Equals … это потому, что тип ожидаемого значения всегда известен автору теста, в то время как тип фактического значения может быть неизвестен.

5. Кроме того, имейте в виду, что у NUnit есть свое собственное определение равенства, которое немного отличается как от математического, так и от обычного равенства языков программирования. это кажется оправданным из-за того, как утверждения о равенстве используются в тестах. В частности, утверждение равенства асимметрично как с точки зрения побочных эффектов (например, сообщение об ошибке), так и фактического результата (например, два массива равны, если содержимое одинаково). К сожалению, это тонкий момент, который обычно не обнаруживается до тех пор, пока не пройдет несколько лет использования. 🙁