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