【问题标题】:Unit Test Assert.AreEqual failed单元测试 Assert.AreEqual 失败
【发布时间】:2011-06-13 08:35:09
【问题描述】:

我对从集合中获取对象的方法进行了单元测试。这一直失败,我不明白为什么,所以我在下面创建了一个非常简单的测试来创建 2 个供应商对象并测试它们是否相等,看看我是否可以在我的代码测试中发现问题。但是这个测试又失败了。任何人都可以看到或解释原因吗?

    [TestMethod()]
    public void GetSupplierTest2()
    {
        Supplier expected = new Supplier();
        expected.SupplierID = 32532;
        expected.SupplierName = "Test 1"

        Supplier actual = new Supplier();
        actual.SupplierID = 32532;
        actual.SupplierName = "Test 1"

        Assert.AreEqual(expected, actual);
    }

但是,如果我测试对象的各个属性,则测试通过...

    [TestMethod()]
    public void GetSupplierTest2()
    {
        Supplier expected = new Supplier();
        expected.SupplierID = 32532;
        expected.SupplierName = "Test 1"

    Supplier actual = new Supplier();
        actual.SupplierID = 32532;
        actual.SupplierName = "Test 1"

        Assert.AreEqual(expected.SupplierID , actual.SupplierID );
        Assert.AreEqual(expected.SupplierName , actual.SupplierName );
    }

【问题讨论】:

    标签: .net unit-testing mstest assert


    【解决方案1】:

    正如所有其他答案所说,问题是您正在尝试比较 Supplier [可能] 的实例而不覆盖 Equals 方法。 但我认为您不应出于测试目的覆盖 Equals,因为它可能会影响生产代码,或者您可能需要在生产代码中使用另一个 Equals 逻辑。

    相反,您应该像在第一个示例中那样逐个声明每个成员(如果您没有很多地方要比较整个对象),或者将此比较逻辑封装在某个类中并使用此类:

    static class SupplierAllFieldsComparer
    {
        public static void AssertAreEqual(Supplier expected, Supplier actual)
        {
            Assert.AreEqual(expected.SupplierID , actual.SupplierID );
            Assert.AreEqual(expected.SupplierName , actual.SupplierName );            
        }
    }
    

    // 测试代码:

    SupplierAllFieldsComparer.AssertAreEqual(expected, actual);
    

    【讨论】:

    【解决方案2】:

    如果要比较 Supplier 的两个不同实例,并希望在某些属性具有相同值时将它们视为相等,则必须覆盖 Supplier 上的 Equals 方法并在方法中比较这些属性。

    您可以在此处阅读有关 Equals 方法的更多信息:http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

    示例实现:

    public override bool Equals(object obj)
    {
        if (obj is Supplier)
        {
            Supplier other = (Supplier) obj;
            return Equals(other.SupplierID, this.SupplierID) && Equals(other.SupplierName, this.SupplierName);
        }
        return false;
    }
    

    请注意,您还会收到一个编译器警告,提示您也必须实现 GetHashCode,这可能很简单:

    public override int GetHashCode()
    {
        return SupplierID;
    }
    

    【讨论】:

    • 您能否详细介绍一下重写 Equals 方法?
    【解决方案3】:

    引用类型(即类)的Object.Equals 的默认实现是“引用平等”:这两个对象实际上是相同 实例。它不比较字段的值。

    要么(如其他人所示)覆盖Equals 以提供“价值平等”。在这种情况下,您还必须覆盖GetHashCode(这样容器才能工作),并且应该覆盖operator ==

    或者接受大多数实体应该具有引用相等性(具有相同名称的两个供应商并不总是同一个组织)并实际直接使用属性。

    【讨论】:

      【解决方案4】:

      您比较了 Supplier 类型的 2 个不同实例,这就是 Assert 失败的原因。

      如果你想供应商是平等的说(通过他们的Id)你可以覆盖Equals方法,这里非常简单的例子,:D。

      public class Supplier
      {
          private int id;
          private string name;
      
          public int Id
          {
              get { return id; }
          }
      
          public string Name
          {
              get { return name; }
          }
      
          public bool Equals(Supplier other)
          {
              if(other == null) return false;
              return other.id == id;
          }
      
          public override bool Equals(object obj)
          {
              if(obj == null) return false;
              if (obj.GetType() != typeof (Supplier)) return false;
              return Equals((Supplier) obj);
          }
      
          public override int GetHashCode()
          {
              return id;
          } 
      }
      

      【讨论】:

      • 谢谢,那么您将如何对这样的场景进行单元测试呢?仅比较每个属性的值是正确的方法,还是有一种方法可以将对象与对象进行比较?
      • 你可以覆盖 Equals 函数
      • 你能稍微扩展一下吗?
      【解决方案5】:

      在测试单个属性时,您会比较字符串/整数值。它们是相等的,所以测试通过了。

      在测试父对象时,您只比较供应商类型的两个容器结构 - 即使它们可能具有相同的属性值,但它们并不相等:因为您正在实例化两个单独的对象,所以它们不会位于相同的位置内存中的地址。

      【讨论】:

      • 谢谢,那么您将如何对这样的场景进行单元测试呢?有没有比较对象和对象的方法?
      • 正如其他两个发帖人所建议的那样,您可以覆盖 Supplier 类型的 Equals 方法并让它比较各个属性值。请参阅本教程,例如:msdn.microsoft.com/en-us/library/336aedhh(v=vs.71).aspx
      【解决方案6】:
      //Given the following structure and an instance value, targetObj...
      
      class BaseType
      {
         private FeatureType Feature_1;
      }
      
      class TargetType : BaseType 
      {
        ...
      }
      
      TargetType targetObj = new TargetType();
      
      //...a private feature in a specific base class can be accessed as follows
      
      PrivateType typeCast = new PrivateType(typeof( BaseType ));
      
      PrivateObject privateObj = new PrivateObject(targetObj, typeCast);
      
      //...and values can be retrieved and set as follows....
      
      privateObj.SetField("Feature_1", (FeatureType) newValue );
      
      FeatureType result = (FeatureType) privateObj.GetField("Feature_1");
      

      /* 关于在单元测试中访问私有字段的争议,我认为除非绝对必要(即时间和费用管理问题),否则绝不应该使用它。 */

      【讨论】:

        猜你喜欢
        • 2023-04-07
        • 2012-08-17
        • 1970-01-01
        • 1970-01-01
        • 2014-05-04
        • 1970-01-01
        • 1970-01-01
        • 2021-12-15
        • 2020-02-14
        相关资源
        最近更新 更多