Ошибка NUnit? ожидаемый <mytype> Но было <mytype>
[Test]
public void testMultiplication()
{
var five=new Dollar(5);
Assert.AreEqual(new Dollar(10), five.times(2));
Assert.AreEqual(new Dollar(15), five.times(3));
}
Долларовый класс
public class Dollar
{
private int amount;
public Dollar(int amount)
{
this.amount = amount;
}
public Dollar times(int multiplier)
{
return new Dollar(amount * multiplier);
}
public bool equals(Object theObject)
{
Dollar dollar = (Dollar) theObject;
return amount == dollar.amount;
}
}
On line Assert.AreEqual (новый доллар (10), пять (2)); ошибка теста с ошибкой:
Ожидаемые: TDDbooks.Dollar
Но было: TDDbooks.Dollar
Ответы
Ответ 1
NUnit отображает строковое представление объектов. Чтобы иметь удобный выход, вы должны переопределить метод ToString
класса Dollar
:
public override string ToString()
{
return "$" + amount;
}
Теперь вывод будет выглядеть так:
Expected: $10
But was: $10
Следующая проблема - сравнение долларов. NUnit сравнивает объекты, вызывая метод Equals
(не equals
, но Equals
. Кент Бек использует Java в своих примерах. В С# у нас есть имена Pascal для методов). Реализация по умолчанию метода Equals
возвращает true, если объекты имеют одинаковую ссылку. Но в методе Times
вы создаете новый экземпляр класса Dollar
. Чтобы исправить это, вы должны изменить реализацию метода Equals
чтобы сравнить количество полей.
public override bool Equals(object obj)
{
Dollar other = obj as Dollar;
if (other == null)
return false;
return amount == other.amount;
}
Также обратите внимание, что вы должны использовать ключевое слово override
для переопределения функциональности базового класса. И еще одно - когда вы переопределяете функциональность Equals
, вы должны переопределить метод GetHashCode
. В вашем случае это нормально, чтобы иметь что-то вроде:
public override int GetHashCode()
{
return amount.GetHashCode();
}
Ответ 2
Метод Assert.AreEquals
будет использовать метод Equals
для проверки равенства. Вместо переопределения Object.Equals
тип Dollar
просто определяет новый метод equals
, который не участвует в равенстве.Net объекта. Следовательно, он не используется, и в тесте используется ссылочное равенство, которое не выполняется. Чтобы исправить это, вам необходимо переопределить метод Object.Equals
public override bool Equals(object obj) {
Dollar other = obj as Dollar;
if (other == null) {
return false;
}
return amount == other.amount;
}
Ответ 3
Там пара вещей:
- Вы определили новый метод
equals
, вместо того, чтобы переопределять метод базового класса Equals
. Переключитесь на переопределение, и NUnit вызовет ваш метод. - NUnit выводит объект с помощью
ToString
, а реализация ToString по умолчанию - просто напечатать имя класса. Переопределите ToString
чтобы напечатать сумму, и сообщение подтверждения будет иметь больший смысл.
Ответ 4
Вы утверждаете, что new Dollar(10)
- это тот же объект, что и тот, который возвращается five.times(2)
, что неверно.
Если вы хотите утверждать таким образом, вам нужно будет перегрузить метод Equals в вашем классе Dollar следующим образом:
public override bool Equals(Object obj)
{
if (obj is Dollar)
{
return this.Amount == ((Dollar)obj).Amount;
}
return false;
}
Вы не используете ключевое слово override
в методе Equals
.
Ответ 5
Лучшее решение уже было предложено несколькими людьми, но есть альтернатива, которая может работать в других ситуациях. Вам нужно будет добавить getter для поля amount
так:
public int Amount { get { return amount; } }
И тогда, когда вы выполните единичный тест, это будет выглядеть так:
Assert.AreEqual(10, five.times(2).Amount);
Итак, теперь вы сравниваете int
с другим int
. В качестве альтернативы вы можете сделать переменную amount
общедоступной, хотя это и разрушает инкапсуляцию. Очевидно, что использование метода Equals
является лучшим способом в этом случае, но в некоторых ситуациях это может быть предпочтительным.