【问题标题】:Object Comparison in Unit Testing单元测试中的对象比较
【发布时间】:2011-01-13 13:07:00
【问题描述】:

我的单元测试中有两个对象,实际对象和预期对象。对象方法的所有属性都完全相同,如果我运行以下测试:

Assert.AreEqual( expectedObject.Property1, actualObject.Property1);

结果按预期通过。但是,当我尝试运行以下测试时,它失败了:

Assert.AreEqual (expectedObject, actualObject);

我错过了什么?不能比较两个对象吗?我必须检查每个属性吗?

【问题讨论】:

  • 这里有一个对 NUnit 有帮助的类似问题:stackoverflow.com/questions/318210/…
  • 为了实际执行您想要的工作,我编写了一个实用程序类,它通过使用反射来比较两个对象的属性。目前我手头没有代码,但是实现这样的功能并不难。
  • 如果你遇到了 Juri 的代码,我很想看看你做了什么。

标签: .net mstest


【解决方案1】:

您需要为您的对象覆盖EqualsAssert 使用 Object.Equals。默认情况下,Object.Equals 对引用类型的对象执行引用比较。也就是说,一个引用类型的两个实例当且仅当它们引用同一个对象时才相等。您想要覆盖它,以便执行值比较而不是执行参考比较。这是一个非常好的MSDN article 关于这个主题。请注意,您还需要覆盖GetHashCode。请参阅 guidelines 的 MSDN。这是一个简单的例子:

之前:

class Test {
    public int Value { get; set; }
}

Test first = new Test { Value = 17 };
Test second = new Test { Value = 17 };
Console.WriteLine(first.Equals(second)); // false

之后:

class Test {
    public int Value { get; set; }
    public override bool Equals(object obj) {
        Test other = obj as Test;
        if(other == null) {
            return false; 
        }
        return this.Value == other.Value;
    }
    public override int GetHashCode() { 
        return this.Value.GetHashCode();
    }
}

Test first = new Test { Value = 17 };
Test second = new Test { Value = 17 };
Console.WriteLine(first.Equals(second)); // true

【讨论】:

【解决方案2】:

第二个断言语句实际上比较的是对象的引用,而不是内容。由于 AreEqual 方法的参数是对象类型,所以没有太多关于单元测试框架应该如何比较它们的信息。

编辑:检查这个问题:Compare equality between two objects in NUnit

【讨论】:

  • 啊..太晚了 :) 只是写了一样的 :) (+1)
  • 啊,好电话。我发帖时没有看到 nUnit 问题。
【解决方案3】:

除非您已将“=”符号重载到您的对象,否则您不能使用它。在您的对象类中,您需要执行以下操作:


public override bool Equals(object obj)
{
   if(obj == null)
      return false;
   return (this.Property1 == obj.Property1 && 
          this.Property2 == obj.Property2);
}

如果您不这样做,那么您只是在比较对象引用。

【讨论】:

    【解决方案4】:

    这是真的。两个对象是否相等完全取决于其 Equals 方法的实现。有时使用 Equal 方法,覆盖 GetHashCode 实现也很好。如果它没有被覆盖,那么(Object 类的)默认虚拟实现将与 Equal 方法的评估一起被考虑。对于被认为相等的对象,它们的哈希码应该相同。

    但是对于单元测试,我建议不要过度依赖 Equal 方法的实现。无论您想确定自己比较对象的这些属性的任何属性,因为 Equal 方法可能是自定义实现,因此它可能在一天结束时包含错误。所以更好地信任系统定义类的 Equal 方法进行单元测试。

    【讨论】:

      【解决方案5】:

      Deepak :这意味着在一天结束时我不会比较对象。比较对象属性值。正确..这种相等的覆盖方法仅适用于特定对象...这是限制而不是正确的方法...

      这是一个很好的链接...在准备 UnitTest 之前,为测试帮助创建自己的类

      http://manfred-ramoser.blogspot.com/2007/11/c-unit-testing-helper.html

      【讨论】:

        【解决方案6】:

        https://github.com/kbilsted/StatePrinter 专门用于将对象图转储为字符串表示,目的是编写简单的单元测试。

        • 它带有 witg Assert 方法,可以输出正确转义的字符串,轻松复制粘贴到测试中以更正它。
        • 它允许自动重写单元测试
        • 它与所有单元测试框架集成
        • 与 JSON 序列化不同,支持循环引用
        • 您可以轻松过滤,因此只转储部分类型

        给定

        class A
        {
          public DateTime X;
          public DateTime Y { get; set; }
          public string Name;
        }
        

        您可以以类型安全的方式,并使用 Visual Studio 的自动完成包含或排除字段。

          var printer = new Stateprinter();
          printer.Configuration.Projectionharvester().Exclude<A>(x => x.X, x => x.Y);
        
          var sut = new A { X = DateTime.Now, Name = "Charly" };
        
          var expected = @"new A(){ Name = ""Charly""}";
          printer.Assert.PrintIsSame(expected, sut);
        

        【讨论】:

          【解决方案7】:

          这是典型的等价问题,看起来接受的答案不是一个好的答案。我会尝试解释原因。

          想象以下情况 - 您必须在后端编写集成测试以确保它正确存储您的域对象。 你有一个代码:

          [TestMethod]
              [Description(@"Sequentially perform operations
                           1. Save new item in DB
                           2. Get same Item from DB
                           Ensure that saved and get Items are equivalent")]
              public void Repository_Create_Test()
              {
                  var initialItem = GetTestItem();
                  //create item and check it is created correct
                  initialItem.ID = repository.Create(initialItem, userID, ownerID);
                  Item resultItem = repository.GetById(initialItem.ID, ownerID);
                  resultItem.Should().NotBeNull();
                  Assert.AreEqual(initialItem, resultItem);
              }
          

          因此,您需要验证从存储中读取的对象与我们发送到存储中的对象是否绝对等效。覆盖Equals 是一个简单的初步猜测。对于这种情况,我们需要设置Equals 来比较所有对象字段。但从 DDD 的角度来看,这完全是错误的。域实体通过不可变键(或主键)而不是所有可变字段来区分。因此,如果我们在 HR 领域建模并且假设“X 先生”有一个新的电话号码,他仍然是“X 先生”。

          话虽如此,我目前正在使用FluentAssertions 框架,它具有相当强大的等效性检查功能。像这样:

          resultItem.ShouldBeEquivalentTo(initialItem);
          

          【讨论】:

            【解决方案8】:

            我知道这是一个老问题,但是当我阅读答案时,我想到了一个简单的技巧。也许其他人已经知道这个 hack,但由于这里没有提到它......

            我已经将 Newtonsoft.Json 作为我项目的一部分。因此,我可以轻松地在预期和实际上使用 JsonConvert.SerializeObject(obj)。那么它只是 Assert.AreEqual 两个字符串。

            为我工作:)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-02-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-12-07
              相关资源
              最近更新 更多