Ошибка 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

Там пара вещей:

  1. Вы определили новый метод equals, вместо того, чтобы переопределять метод базового класса Equals. Переключитесь на переопределение, и NUnit вызовет ваш метод.
  2. 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 является лучшим способом в этом случае, но в некоторых ситуациях это может быть предпочтительным.