I'm working through Kent Beck's TDD by Example as an academic exercise, but using MSpec to write the tests. When following worked examples, I like to introduce a twist so that I can't simply copy the text out rote, I find that way I tend to run into problems that I have to solve and as a result, end up learning much more. I believe this is one of those occasions.
I'm part way through Kent's 'money' example. Here's the class structure I have:
I have the following two test contexts:
[Subject(typeof(Money), "Equality")]
public class when_comparing_different_classes_for_equality
{
Because of = () => FiveFrancs = new Franc(5, "CHF");
It should_equal_money_with_currency_set_to_francs = () => FiveFrancs.Equals(new Money(5, "CHF")).ShouldBeTrue();
static Franc FiveFrancs;
}
[Subject(typeof(Franc), "multiplication")]
public class when_multiplying_a_franc_amount_by_an_integer
{
Because of = () => FiveFrancs = new Franc(5, null);
It should_be_ten_francs_when_multiplied_by_2 = () => FiveFrancs.Times(2).ShouldEqual(Money.Franc(10));
It should_be_fifteen_francs_when_multiplied_by_3 = () => FiveFrancs.Times(3).ShouldEqual(Money.Franc(15));
static Franc FiveFrancs;
}
The Times() method returns a new object of type Money containing the result, i.e. the objects are immutable. the first context above passes, suggesting that Equals is working as expected, i.e. it ignores the the object types, so long as they are both inherited from Money, and only compares that the amount and currency fields are equal. The second context fails with output similar to this:
Machine.Specifications.SpecificationException
Expected: TDDByExample.Money.Specifications.Franc:[15]
But was: TDDByExample.Money.Specifications.Money:[15]
at TDDByExample.Money.Specifications.when_multiplying_a_franc_amount_by_an_integer.<.ctor>b__2() in MoneySpecs.cs: line 29
Equality is defined as the amount (value) and currency being the same; the actual type of the object is supposed to be ignored, so the intended result is that it shouldn't matter if I'm testing equality with Money or Franc objects, as long as the amount and currency fields are the same. However, things are not working as planned. When debugging, my Equals() methods are not even getting called. There is clearly something I'm not understanding here. I am sure the solution will be blindingly obvious when I know it, but I can't see it for looking. Can anyone offer a suggestion as to what I need to do to make this work?
Here's the implementation of Equals():
public bool Equals(Money other)
{
return amount == other.amount && currency == other.currency;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return Equals(obj as Money);
}
In Java terms, they are equal, which is checked with equals : String some = "some string"; String other = "some string"; boolean equal = some. equals(other); Here, equals is true .
equals() method: This method is used to check whether 2 objects are equal or not. This method is provided by the Object class. You can override this in your class to provide your implementation. HashMap uses equals() to compare the key to whether they are equal or not.
The equals() method compares two strings, and returns true if the strings are equal, and false if not. Tip: Use the compareTo() method to compare two strings lexicographically.
We can use == operators for reference comparison (address comparison) and . equals() method for content comparison. In simple words, == checks if both objects point to the same memory location whereas . equals() evaluates to the comparison of values in the objects.
A fully-complete implementation of equality would look like this. See if it helps.
protected bool Equals(Money other)
{
// maybe you want this extra param to Equals?
// StringComparison.InvariantCulture
return amount == other.amount
&& string.Equals(currency, other.currency);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
var other = obj as Money;
return other != null && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (amount * 997) ^ currency.GetHashCode();
}
}
public static bool operator ==(Money left, Money right)
{
return Equals(left, right);
}
public static bool operator !=(Money left, Money right)
{
return !Equals(left, right);
}
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