【问题标题】:NUnit test Bug? Expected <MyType> But was <MyType>NUnit 测试错误?预期 <MyType> 但是 <MyType>
【发布时间】:2012-10-22 15:12:42
【问题描述】:
[Test]
public void testMultiplication()
{
    var five=new Dollar(5);
    Assert.AreEqual(new Dollar(10), five.times(2));
    Assert.AreEqual(new Dollar(15), five.times(3));
}

美元类

public class Dollar
{
    private int amount;

    public Dollar(int amount)
    {
        this.amount = amount;
    }

    public Dollar times(int multiplier)
    {
        return new Dollar(amount * multiplier);
    }

    public bool equals(Object theObject)
    {
       Dollar dollar = (Dollar) theObject;

       return amount == dollar.amount;
    }
}

在线 Assert.AreEqual(new Dollar(10), Five.times(2));测试失败并出现错误:

预期:TDDbooks.Dollar

但是是:TDDbooks.Dollar

【问题讨论】:

  • 旁白:为什么不实现运算符重载?
  • 看起来可能是程序集版本问题;您是否可能有两个版本的程序集实现 TDDbooks.Dollar 已加载?

标签: c# unit-testing nunit


【解决方案1】:

Assert.AreEquals 方法将使用Equals 方法来测试相等性。 Dollar 类型没有覆盖Object.Equals,而是定义了一个不参与.Net 对象相等性的新equals 方法。因此它没有被使用,并且测试使用了失败的引用相等。要解决此问题,您需要覆盖 Object.Equals 方法

public override bool Equals(object obj) { 
  Dollar other = obj as Dollar;
  if (other == null) {
    return false;
  }

  return amount == other.amount;
}

【讨论】:

    【解决方案2】:

    NUnit 显示对象的字符串表示。为了方便输出,您应该重写 Dollar 类的 ToString 方法:

    public override string ToString()
    {
       return "$" + amount;
    }
    

    现在输出会是这样的:

    Expected: $10 
    But was: $10
    

    下一个问题是美元比较。 NUnit 通过调用Equals 方法比较对象(不是equals,而是Equals。Kent Beck 在他的示例中使用 Java。在 C# 中,我们为方法使用 Pascal 命名)。如果对象具有相同的引用,Equals 方法的默认实现将返回 true。但是在Times 方法中,您创建了Dollar 类的新实例。为了解决这个问题,您应该更改 Equals 方法实现以比较金额字段。

    public override bool Equals(object obj)
    { 
      Dollar other = obj as Dollar;
      if (other == null)
        return false;  
    
      return amount == other.amount;
    }
    

    另外请注意,您应该使用override 关键字来覆盖基类功能。还有一件事——当你覆盖Equals 功能时,你应该覆盖GetHashCode 方法。在你的情况下,可以有类似的东西:

    public override int GetHashCode()
    {
      return amount.GetHashCode();
    }
    

    【讨论】:

    • 另外,如果您不打算从Dollar 类派生,请考虑将其设为sealed。如果您不使用sealed,请考虑在Equals 方法中使用if (GetType() != other.GetType()) return false;。否则,如果other 是更派生类型的Dollar(如DescriptionDollar),您可能会得到不好的结果。
    【解决方案3】:

    有几件事:

    1. 您定义了一个新方法equals,而不是覆盖基类方法Equals。切换到覆盖,NUnit 将调用您的方法。
    2. NUnit 使用它的ToString 打印出对象,而 ToString 的默认实现是简单地打印类名。覆盖 ToString 以打印金额,断言消息将更有意义。

    【讨论】:

      【解决方案4】:

      您在那里断言的是 new Dollar(10)five.times(2) 返回的对象相同,这是不正确的。

      如果你想以这种方式断言,你需要像这样在你的 Dollar 类中重载 Equals 方法:

       public override bool Equals(Object obj)
       {
           if (obj is Dollar)
           {
               return this.Amount == ((Dollar)obj).Amount;
           }
           return false;
       }
      

      您没有在 Equals 方法中使用 override 关键字。

      【讨论】:

        【解决方案5】:

        一些人已经给出了最佳解决方案,但还有一种替代方案可能适用于其他情况。您需要为 amount 字段添加一个吸气剂,如下所示:

        public int Amount { get { return amount; } }
        

        然后当你进行单元测试时,它看起来像:

        Assert.AreEqual(10, five.times(2).Amount);
        

        所以现在您将int 与另一个int 进行比较。或者,您可以将 amount 变量公开,但这会破坏封装。显然,在这种情况下,正确使用 Equals 方法是更好的方法,但在某些情况下,这可能更可取。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-11
          • 1970-01-01
          • 2011-09-01
          相关资源
          最近更新 更多