#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);
Первые два утверждения проходят, а следующие два терпят неудачу.
- По-видимому, существует разница во внутренней работе каждого утверждения. Может кто-нибудь объяснить, что это такое?
- Точнее, отладка с точками останова, по-видимому, указывает на эти
Assert.That("Comment", Is.EqualTo(_objOrder2.OrderComment))
тесты_objOrder2.OrderComment.Equals("Comment")
; я бы ожидал, что все будет наоборот. Я что-то упускаю? - Я это понимаю
True()
иEquals()
старше, чемThat()
. Какие из них предпочтительнее в каких ситуациях?
Комментарии:
1.
Is.EqualTo
иEquals
проверяет также тип объекта, а не просто логическое условие, стоящее за ним. Поэтому имеет смысл, что ваше свойство пользовательского объекта не равно System. Строка, так как она другого типа.
Ответ №1:
Здесь играют 2 вещи:
- Насколько полезно сообщение об ошибке от NUnit в случае сбоя теста
- Какой стиль 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 есть свое собственное определение равенства, которое немного отличается как от математического, так и от обычного равенства языков программирования. это кажется оправданным из-за того, как утверждения о равенстве используются в тестах. В частности, утверждение равенства асимметрично как с точки зрения побочных эффектов (например, сообщение об ошибке), так и фактического результата (например, два массива равны, если содержимое одинаково). К сожалению, это тонкий момент, который обычно не обнаруживается до тех пор, пока не пройдет несколько лет использования. 🙁