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
}
}
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:
Currency
to be a property, not a methodAmount
propertyamount
to be decimal
instead of int
Times
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?
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With