NUnit doesn't work well with Assert.AreEqual

两盒软妹~` 提交于 2019-12-19 13:45:38

问题


I'm new to unit testing and NUit in particular. I'm just typing some examples from the book which refers to Java and JUnit. But I'm using C# instead.

The problem is: I've got a class with overriden methods such as Equals() and GetHashCode(), but when I am trying to compare two objects of this class with Assert.AreEqual() my code is not called, so I get an exception.

Assert.True(MyClass.Equals(MyClass2)) does work well. But I don't want to use this construction instead of Assert.AreEqual(). Where can the problem be?

Here is the class:

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;
    }
}

And the test method itself:

[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:


The problem is you're hiding Equals, not overriding it. Well done - your unit test has found a bug :)

Your code should be:

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

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

(This will prevent it from throwing an exception if you give it the wrong type, too.)

I've made the string equality test simpler too - operator overloading can be very helpful :)

By the way, you almost certainly want to:

  • Change Currency to be a property, not a method
  • Add an Amount property
  • Probably change the type of amount to be decimal instead of int
  • Make the fields private and readonly
  • Seal the class
  • Add operator overloads for == and !=
  • Possibly add a * operator overload to do the same as Times
  • Avoid string formatting when calculating the hash (there are dozens of answers showing better hash implementations)

EDIT: I've just reread that you're using an example from a book. Does the book really hide instead of overriding the Equals method? I suggest you get a new book, if so (unless it's being a deliberate example of when it's wrong to use hiding!)... which book is it?




回答2:


I found it confusing that implementing the IEquatable interface, which also has an

Equals(T other)

method, posed me with the same problem as described above.

The only reason I chose to use the IEquaytable interface above overriding the Equals method was not to have to do the type check.

In the end I had to use the following code

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;
}

but then I thought, why not just leave the IEquatable interface for what it is and only override the Equals method. (less code = better)




回答3:


I suspect your problem is that you haven't overridden overload the equality == operator. Under the hood the Assert.AreEqual is probably using ==.

See Operator Overloading Tutorial.

Update: I ran the NUnit test through the debugger and it does indeed use the Equals method and not the == operator.




回答4:


You can write framework agnostic asserts using a library called Should. It also has a very nice fluent syntax which can be used if you like fluent interfaces. I had a blog post related to the same.

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



来源:https://stackoverflow.com/questions/1373358/nunit-doesnt-work-well-with-assert-areequal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!