我的单元测试中有两个对象,即实际和预期的对象。对象方法的所有属性都完全相同,如果我运行以下测试:
Assert.AreEqual( expectedObject.Property1, actualObject.Property1);
结果按预期传递。但是,当我尝试运行以下测试时,它失败了:
Assert.AreEqual (expectedObject, actualObject);
我错过了什么?可以不比较两个对象,我是否必须对每个属性进行检查?
答案 0 :(得分:15)
您需要覆盖对象的Equals
。 Assert
使用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
答案 1 :(得分:4)
第二个assert语句实际上比较了对象的引用,而不是内容。由于AreEqual方法的参数是类型对象,因此关于单元测试框架应如何比较这些参数的信息并不多。
答案 2 :(得分:1)
除非您将其重载到对象上,否则无法使用“=”符号。在您的对象类中,您需要执行以下操作:
public override bool Equals(object obj)
{
if(obj == null)
return false;
return (this.Property1 == obj.Property1 &&
this.Property2 == obj.Property2);
}
如果你不这样做,那么你只是简单地比较对象引用。
答案 3 :(得分:1)
这是事实。两个对象是否相等完全取决于它的Equals方法的实现。有时使用Equal方法,覆盖GetHashCode实现也是很好的。如果它不是覆盖,则将考虑默认的虚拟实现(Object类)以及Equal方法的评估。对于被认为相等的对象,它们的哈希码应该是相同的。
然而,对于单元测试,我建议不要严重依赖Equal方法的实现。无论您想要确定哪个属性都要自己比较对象的这些属性,因为Equal方法可能是自定义实现,因此有可能在一天结束时包含错误。因此,更好地信任系统定义的类的Equal方法进行单元测试。
答案 4 :(得分:0)
Deepak:这意味着在一天结束时我不会比较对象。比较对象属性值。正确..这个相等的覆盖方法仅适用于特定的对象...这是限制而不是正确的方式......
这里有好的链接......在准备之前,UnitTest会为测试帮助创建自己的类
http://manfred-ramoser.blogspot.com/2007/11/c-unit-testing-helper.html
答案 5 :(得分:0)
https://github.com/kbilsted/StatePrinter专门用于将对象图转储为字符串表示,目的是编写简单的单元测试。
鉴于
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);
答案 6 :(得分:0)
那个典型的等价问题看起来像是接受的答案并不是一个好问题。我会尝试解释原因。
想象一下以下内容 - 您必须在后端编写集成测试,以确保它正确存储您的域对象。 你有一个代码:
[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的角度来看,这是完全错误的。域实体由不可变密钥(或主键)区分,而不是由所有可变字段区分。因此,如果我们正在建立人力资源领域和假设的先生X&#39;有一个新的电话号码,他仍然是同一个&#39;先生X&#39;。
所有这一切,我目前正在使用FluentAssertions框架,它具有相当强大的等效性检查功能。像这样:
resultItem.ShouldBeEquivalentTo(initialItem);