我正在通过Kent Beck的TDD作为学术练习,但是使用MSpec来编写测试。在下面的工作示例中,我想介绍一个扭曲,以便我不能简单地将文本复制出来,我发现这种方式我倾向于遇到我必须解决的问题,因此,最终学习更多。我相信这是其中一种情况。
我通过Kent的'钱'示例的一部分。这是我的类结构:
我有以下两个测试环境:
[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()方法返回一个包含结果的Money类型的新对象,即对象是不可变的。上面的第一个上下文传递,表明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
平等定义为金额(价值)和货币相同;应该忽略对象的实际类型,因此预期的结果是,如果我正在测试与Money或Franc对象的相等性,只要金额和货币字段相同,则无关紧要。但是,事情没有按计划进行。调试时,我的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);
}
答案 0 :(得分:2)
完全相同的实现将如下所示。看看它是否有帮助。
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);
}
答案 1 :(得分:0)
正如@Harrison评论的那样,问题是Times
类的Franc
方法的结果类型。它未通过测试规范,因为它返回Money
对象,但规范需要Franc
实例。更改规范以要求Money
对象或覆盖Times
方法以返回Franc
实例。
<强>更新强>
更新测试规范后,您更改了行:
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));
但是,在属性上,主题的类型仍然是:
[Subject(typeof(Franc), "multiplication")]
所以我认为它仍然期待Franc
实例而不是Money
实例。