NUnit не работает с Assert.AreEqual

Я новичок в модульном тестировании и в частности NUit. Я просто набираю несколько примеров из книги, которая относится к Java и JUnit. Но вместо этого я использую С#.

Проблема в том, что у меня есть класс с переопределенными методами, такими как Equals() и GetHashCode(), но когда я пытаюсь сравнить два объекта этого класса с Assert.AreEqual(), мой код не вызывается, поэтому я получить исключение.

Assert.True(MyClass.Equals(MyClass2)) работает хорошо. Но я не хочу использовать эту конструкцию вместо Assert.AreEqual(). Где может быть проблема?

Вот класс:

public class Money
{
    public int amount;
    protected string currency;

    public Money(int amount, string currency)
    {
        this.amount = amount;
        this.currency = currency;
    }

    public new bool Equals(object obj)
    {
        if (obj == null)
            return false;

        Money money = (Money)obj;
        return (amount == money.amount)
                && (Currency().Equals(money.Currency()));
    }

    public new int GetHashCode()
    {
        return (string.Format("{0}{1}", amount, currency)).GetHashCode();
    }

    public static Money Dollar(int amount)
    {
        return new Money(amount, "USD");
    }
    public static Money Franc(int amount)
    {
        return new Money(amount, "CHF");
    }

    public Money Times(int multiplier)
    {
        return new Money(amount * multiplier, currency);
    }

    public string Currency()
    {
        return currency;
    }
}

И сам метод тестирования:

[TestFixture]
public class DollarTest
{
    [Test]
    public void TestMultiplication()
    {
        Money five = Money.Dollar(5);
        Assert.True(Money.Dollar(10).Equals(five.Times(2)));  // ok
        Assert.AreEqual(Money.Dollar(10), five.Times(2));     // fails
    }
}

Ответ 1

Проблема в том, что вы скрываете Equals, а не переопределяете ее. Молодцы - ваш unit test нашел ошибку:)

Ваш код должен быть:

public override bool Equals(object obj)
{
    Money money = obj as Money;
    if (money == null)
        return false;

    return (amount == money.amount && currency == money.currency);
}

(Это предотвратит его отбрасывание исключения, если вы также присвоите ему неправильный тип.)

Я также упростил проверку равенства строк - перегрузка оператора может быть очень полезной:)

Кстати, вы почти наверняка хотите:

  • Измените Currency как свойство, а не метод
  • Добавить свойство Amount
  • Вероятно, измените тип Amount на decimal вместо int
  • Сделать поля приватными и readonly
  • Запечатать класс
  • Добавить перегрузки операторов для == и!=
  • Возможно, добавлена ​​перегрузка оператора *, чтобы сделать то же самое, что и Times
  • Избегайте форматирования строк при вычислении хэша (есть десятки ответов, показывающих лучшие реализации хэша)

EDIT: Я только перечитал, что вы используете пример из книги. Действительно ли книга скрывается вместо переопределения метода Equals? Я предлагаю вам получить новую книгу, если да (если это не преднамеренный пример того, когда неправильно использовать скрытие!)... в какой книге?

Ответ 2

Я сбив с толку, что реализация интерфейса IEquatable, которая также имеет

Equals(T other)

поставил меня с той же проблемой, как описано выше.

Единственная причина, по которой я решил использовать интерфейс IEquaytable выше переопределения метода Equals, не должен был делать проверку типа.

В конце концов мне пришлось использовать следующий код

public bool Equals(CustomTag other)
{
   return (other.Name.Trim().ToLower() == Name.Trim().ToLower());
}

public override bool Equals(object o)
{
    if (o is CustomTag)
    {
        return Equals(o as CustomTag);
    }
    return false;
}

но потом я подумал, почему бы просто не оставить интерфейс IEquatable для того, что он есть, и только переопределить метод Equals. (меньше кода = лучше)

Ответ 3

Я подозреваю, что ваша проблема в том, что вы не перегружали , чтобы перегрузить оператор равенства ==. Под капотом Assert.AreEqual, вероятно, использует ==.

См. Учебное пособие по перегрузке оператора.

Обновление: я проверил тест NUnit через отладчик, и он действительно использует метод Equals, а не оператор ==.

Ответ 4

Вы можете написать утверждения агностики фреймов, используя библиотеку с именем Should. Он также имеет очень хороший плавный синтаксис, который можно использовать, если вам нравятся плавные интерфейсы. У меня была запись в блоге, связанная с тем же.

http://nileshgule.blogspot.com/2010/11/use-should-assertion-library-to-write.html