Я работаю по TDD Кент Бек по примеру, как академическое упражнение, но используя MSpec для написания тестов. Когда я следую приведенным примерам, мне нравится вводить твист, чтобы я не мог просто скопировать текст из строки, я нахожу, что у меня возникают проблемы, которые я должен решить, и в результате получаю гораздо больше знаний. Я считаю, что это один из тех случаев.Почему мой метод Equals не вызван?
Я частично переживаю пример «денег» Кента. Вот структура класса у меня есть:
У меня есть следующие два теста контексты:
[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;
}
Метод Times() возвращает новый объект типа денег, содержащий результат, то есть объекты неизменны. первый вышеперечисленный контекст, предполагающий, что Equals работает как ожидалось, т. е. игнорирует типы объектов, если они оба унаследованы от Money, и только сравнивает, что сумма и валютные поля равны. Второй контекст выходит из строя с аналогичным результатом:
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
Равенство определяется как сумма (стоимость) и валюта одинакова; предполагается, что фактический тип объекта игнорируется, поэтому предполагаемый результат заключается в том, что не имеет значения, проверяю ли я равенство с объектами «Деньги» или «Франк», если поля суммы и валюты совпадают. Однако все работает не так, как планировалось. При отладке мои методы Equals() даже не вызываются. Очевидно, что-то я не понимаю здесь. Я уверен, что решение будет ослепительно очевидным, когда я это знаю, но я не вижу его для поиска. Может ли кто-нибудь предложить предложение о том, что мне нужно сделать, чтобы сделать эту работу?
Вот реализация 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);
}
После большого рассмотрения, я считаю, что это может быть проблема MSpec. MSpec сравнивает типы объектов и отказывает сравнение, основанное на том, что типы не совпадают. Только если типы равны, MSpec затем продолжает использовать сравнение, основанное на значении. Вот почему мой метод Equals никогда не вызывается. Однако, я думаю, Лисков говорит, что я должен иметь возможность сравнивать Деньги с франком, если это позволяет мое определение равенства.Поэтому я открыл проблему с проектом MSpec. https://github.com/machine/machine.specifications/issues/200 –
@ Энтони Я предпочитаю отступы стиля Whitesmiths (скобки с отступом). Я не особо возражаю против того, что вы меняете мой отступ, и я счастлив, что ваши правки стоят, но, с другой стороны, кажется немного самонадеянным переоценивать предпочтения других людей. Есть ли руководство, о котором я не знаю? –
Ой, извините, я просто предполагал, что у вас плохой пробел/табуляция или что-то в этом роде. Я получаю все глянцевые глаза от общего форматирования кода неправильного кода SO. –