Why is my Equals method not called?

I work through Kent Beck TDD as an example as an academic exercise, but using MSpec to write tests. When I follow these examples, I like to enter a twist so that I can’t just copy the text from the line, I find that I am having problems that I have to solve, and as a result I get much more knowledge. I think this is one of those cases.

I partially relive the Kent "money" example. Here I have a class: enter image description here

I have 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. objects are immutable. the first context above, suggesting that Equals is working as expected, i.e. ignores object types if they are both inherited from Money, and only compares that the amount and currency fields are equal. The second context fails with a similar result:

 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 sum (value) and the currency is the same; it is assumed that the actual type of the object is ignored, so the intended result is that it does not matter if I check the equality with the Money or Frank objects if the sum and currency fields match. However, everything does not work as planned. When debugging, my Equals () methods are not even called. Obviously, something I do not understand here. I am sure that the solution will be dazzlingly obvious when I know this, but I do not see it for a search. Can anyone suggest a suggestion on 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); } 
+7
c # tdd mspec
source share
2 answers

The full implementation of equality will look like this. See if this 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); } 
+2
source share

As @Harrison noted, the problem is the result type of the Times method of your Franc class. It does not fulfill the test spec because it returns a Money object, but the spec expects a Franc instance. Either modify the specification that requires the Money object, or override the Times method to return a Franc instance.

Update

After updating the test specification, you changed the lines:

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

But the attribute still has an object type:

 [Subject(typeof(Franc), "multiplication")] 

So, I think he is still expecting a Franc instance instead of a Money instance.

0
source share

All Articles