NUnit与Assert.AreEqual不兼容

我是unit testing的新手,尤其是NUit。 我只是在本书中输入一些引用Java和JUnit的例子。 但我正在使用C#。

问题是:我有一个带有重写方法的类,比如Equals()GetHashCode() ,但是当我试图用Assert.AreEqual()比较这个类的两个对象时,我的代码没有被调用,所以我得到了例外。

Assert.True(MyClass.Equals(MyClass2))确实运行良好。 但我不想使用这种结构而不是Assert.AreEqual() 。 问题出在哪里?

这是class级:

 public class Money { public int amount; protected string currency; public Money(int amount, string currency) { this.amount = amount; this.currency = currency; } public new bool Equals(object obj) { if (obj == null) return false; Money money = (Money)obj; return (amount == money.amount) && (Currency().Equals(money.Currency())); } public new int GetHashCode() { return (string.Format("{0}{1}", amount, currency)).GetHashCode(); } public static Money Dollar(int amount) { return new Money(amount, "USD"); } public static Money Franc(int amount) { return new Money(amount, "CHF"); } public Money Times(int multiplier) { return new Money(amount * multiplier, currency); } public string Currency() { return currency; } } 

而测试方法本身:

 [TestFixture] public class DollarTest { [Test] public void TestMultiplication() { Money five = Money.Dollar(5); Assert.True(Money.Dollar(10).Equals(five.Times(2))); // ok Assert.AreEqual(Money.Dollar(10), five.Times(2)); // fails } } 

问题是你隐藏了 Equals,而不是覆盖它。 做得好 – 你的unit testing发现了一个bug 🙂

你的代码应该是:

 public override bool Equals(object obj) { Money money = obj as Money; if (money == null) return false; return (amount == money.amount && currency == money.currency); } 

(如果你给它错误的类型,这将防止它抛出exception。)

我已经使字符串相等测试更简单 – 运算符重载可能非常有帮助:)

顺便说一下,你几乎肯定想:

  • Currency更改为属性,而不是方法
  • 添加Amount属性
  • 可能会将amount类型更改为decimal而不是int
  • 将字段设为私有和只读
  • 密封课程
  • 为==和!=添加运算符重载
  • 可能会添加*运算符重载以执行与Times相同的操作
  • 在计算哈希时避免字符串格式化(有数十个答案显示更好的哈希实现)

编辑:我刚刚重读你正在使用书中的一个例子。 这本书是否真的隐藏而不是覆盖Equals方法? 我建议你买一本新书,如果是这样的话(除非它是一个故意的例子,说明什么时候使用隐藏是错误的 !)……这本书是哪本书?

我发现实现IEquatable接口也很困惑,它也有一个

 Equals(T other) 

方法,给我带来了与上述相同的问题。

我选择使用上面的IEquaytable接口覆盖Equals方法的唯一原因是不必进行类型检查。

最后我不得不使用以下代码

 public bool Equals(CustomTag other) { return (other.Name.Trim().ToLower() == Name.Trim().ToLower()); } public override bool Equals(object o) { if (o is CustomTag) { return Equals(o as CustomTag); } return false; } 

但后来我想,为什么不离开IEquatable接口,只是覆盖Equals方法。 (更少的代码=更好)

我怀疑你的问题是你没有重写了使用equality ==运算符的重载。 在引擎盖下,Assert.AreEqual可能正在使用==。

请参阅运算符重载教程 。

更新:我通过调试器运行NUnit测试,它确实使用Equals方法而不是==运算符。

您可以使用名为Should的库编写框架无关的断言。 它还有一个非常漂亮的流利语法,如果您喜欢流畅的界面,可以使用它。 我有一篇与之相关的博客文章。

http://nileshgule.blogspot.com/2010/11/use-should-assertion-library-to-write.html