2017-06-29 105 views
2

学习如何使用NUnit编写单元测试。如何使用NUnit单元测试比较复杂对象

努力比较两个复杂的对象。

有一个答案,一个非常类似的问题在这里Comparing Two objects using Assert.AreEqual()虽然它看起来像你预期凌驾于你的对象Equals() - 这是不理想给了我多少的对象有可能是,你想比较,更不用说对象及其嵌套对象上可能存在的属性的数量。

给出的样本对象:

public class AMockObject 
    { 
     public int Id { get; set; } 
     public ICollection<int> Numbers { get; set; } 

     public AMockObject() 
     { 
      Numbers = new List<int>(); 
     }   
    } 

我想比较,这个对象的两个单独的实例具有相同的价值观和我发现Assert.AreEqual()是不是真的做什么我的预期。

例如,所有的这些失败:

// Example 1 
AMockObject a = new AMockObject(); 
AMockObject b = new AMockObject(); 
Assert.AreEqual(a,b); // Fails - they're not equal 

// Example 2 
AMockObject a = new AMockObject() { Id = 1 }; 
AMockObject b = new AMockObject() { Id = 1 }; 
Assert.AreEqual(a, b); // Also fails 

// Example 3 
AMockObject a = new AMockObject() { Id = 1 }; 
a.Numbers.Add(1); 
a.Numbers.Add(2); 
a.Numbers.Add(3);  
AMockObject b = new AMockObject() { Id = 1 }; 
b.Numbers.Add(1); 
b.Numbers.Add(2); 
b.Numbers.Add(3);  
Assert.AreEqual(a, b); // also fails 

我们已制订了代码中我们克隆的各种对象,其中一些非常大的。 鉴于这是一件很常见的事情,有两种测试方法可以测试两个对象在属性值级别是否相同?

这里的例子有两个属性。在现实世界中,我有一个有几十个属性的对象,其中一些属性是其他复杂对象的列表。

目前,我序列化对象和比较字符串,虽然这感觉不太理想。

+0

我认为你的序列化方法可能不是那么糟糕。否则,你会考虑重写平等的东西,或者写一些深刻的复杂的反思。 – Derek

+0

您需要考虑的名单,是1,2,3是否与3,1,2相同?订货是否重要?Xml比较可能最终会有所不同。 – Derek

+0

@Derek - 例如,订单可能无关紧要。虽然只是做一个真正的比较而已。在我的现实世界中,情况并非如此,但这并不是说它不会。 – Darren

回答

2

在单元测试中有一个工具叫做Fluent Assertions,它可以进行这样的比较。

注然而当两个对象图都同样命名的那些无关 对象的类型的属性 具有相同值,

对象是等价的。如果一个类型可以转换为 另一个类型并且结果相等,则两个属性也相等。只要集合实现了 System.Collections.IEnumerable并且集合中的所有项目在结构上相等,则 都将被忽略。请注意,实际行为取决于由FluentAssertions.AssertionOptions管理的全局默认值 。

using FluentAssertions; 

//... 

// Example 1 
AMockObject a = new AMockObject(); 
AMockObject b = new AMockObject(); 
a.ShouldBeEquivalentTo(b); // Asserts that an object is equivalent to another object. 

// Example 2 
AMockObject a = new AMockObject() { Id = 1 }; 
AMockObject b = new AMockObject() { Id = 1 }; 
a.ShouldBeEquivalentTo(b); //Asserts that an object is equivalent to another object. 

// Example 3 
AMockObject a = new AMockObject() { Id = 1 }; 
a.Numbers.Add(1); 
a.Numbers.Add(2); 
a.Numbers.Add(3);  
AMockObject b = new AMockObject() { Id = 1 }; 
b.Numbers.Add(1); 
b.Numbers.Add(2); 
b.Numbers.Add(3); 
a.ShouldBeEquivalentTo(b)  
a.Numbers.ShouldAllBeEquivalentTo(b.Numbers); // Asserts that a collection of objects is equivalent to another collection of objects. 

Documentation here

+0

这看起来超级有趣!谢谢:) - 我没有深入到他们的github,但不知道他们是否序列化对象,因为类型被忽略(在我的情况不是问题) – Darren

+0

再次感谢你NKosi。我们也在踢BDD风格的测试用例,所以这个插槽很好。 – Darren

0

由于没有别的改变,你可以简单地比较创建的对象的属性值?

+0

该示例有2个属性。在现实生活中,我想比较的对象具有超过20个属性,包括包含具有许多属性的其他对象的列表 - 请考虑图形。 – Darren

+0

在我的谦虚经验中,我是这样做的(不管对象属性的数量和复杂度如何,无需修改equals和gethashvalue)。你可以断言它们是同一类的实例(如果在你的场景中有意义),然后根据预定义的预期答案手动检查这些值。 – marto

0

你可以使用反射(见get fields with reflection),并通过在这两个类中的字段进行迭代。 FieldInfo.GetValue()应该为您提供要比较的值。

+0

我假设你使用了反射?有很多代码可以编写,导致错误代码的机会增加。我宁愿不必写一个单元测试来测试我的单元测试:) – Darren

+0

我同意这不是直截了当的,但它是一种制作一个比较规则全部模板的方法。看起来你正在寻找不那么通用,所以这可能是一种矫枉过正。 –

+0

完整的完美比较是我理想中最喜欢和最终需要的。令人惊讶的是,这些领先的测试框架并没有内置任何东西。 – Darren