我如何断言两个任意类型的对象是等价的,而不要求它们相等?

时间:2010-04-12 14:26:23

标签: c# unit-testing generics equivalent

为了实现这一点(但没有这样做)我正在反思预期和实际对象的属性并确保它们的值相等。这可以按预期工作,只要它们的属性是单个对象,即不是列表,数组,IEnumerable ...如果属性是某种类型的列表,则测试失败(在Assert.AreEqual(...)内部for循环)。

public void WithCorrectModel<TModelType>(TModelType expected, string error = "") 
    where TModelType : class
{
    var actual = _result.ViewData.Model as TModelType;
    Assert.IsNotNull(actual, error);
    Assert.IsInstanceOfType(actual, typeof(TModelType), error);
    foreach (var prop in typeof(TModelType).GetProperties())
    {
        Assert.AreEqual(prop.GetValue(expected, null), prop.GetValue(actual, null), error);
    }
}

如果处理一个列表属性,如果我改为使用CollectionAssert.AreEquivalent(...),我会得到预期的结果,但这需要我转换为ICollection,这反过来要求我知道列出的类型,我不(想) 它还要求我知道哪些属性是列表类型,我不知道如何。

那么,我应该如何断言任意类型的两个对象等效

注意:我特意想要要求它们相等,因为一个来自我的测试对象,一个是在我的测试类中构建的比较。

2 个答案:

答案 0 :(得分:1)

这是有效的,不是我真正推荐的,但它有效。

const string methodName = "Boolean SequenceEqual[TSource](System.Collections.Generic.IEnumerable`1[TSource], System.Collections.Generic.IEnumerable`1[TSource])";

var sequenceEqual = 
        typeof(Enumerable)
        .GetMethods()
        .First(m => m.ToString() == methodName);

foreach (var prop in typeof(TModelType).GetProperties())
{        
    var expectedValue = prop.GetValue(expected, null);
    var actualValue = prop.GetValue(actual, null);

    foreach (var item in a.GetType().GetInterfaces())
    {
        if (item.IsGenericType && item.Name.Contains("IEnumerable`1"))
        {
            Assert.IsTrue(
                (bool)sequenceEqual.MakeGenericMethod(
                    item.GetGenericArguments()[0]
                ).Invoke(null, new[] { expectedValue, actualValue })
            );              
        }
    }
}

答案 1 :(得分:1)

不确定这会顺利进行,但一种选择是将对象序列化为字节数组并进行比较。当然,假定您正在处理的对象是可序列化的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace NGTests
{
  class Program
  {
    static void Main(string[] args)
    {
      Person p1 = new Person() { FirstName = "Chris", LastName = "Taylor", Children = { new Person() { FirstName = "Tamrin", LastName = "Taylor" } } };
      Person p2 = new Person() { FirstName = "Chris", LastName = "Taylor", Children = { new Person() { FirstName = "Tamrin", LastName = "Taylor" } } };

      BinaryFormatter formatter = new BinaryFormatter();

      MemoryStream ms1 = new MemoryStream();
      formatter.Serialize(ms1, p1);

      MemoryStream ms2 = new MemoryStream();
      formatter.Serialize(ms2, p2);

      byte[] b1 = ms1.ToArray();
      byte[] b2 = ms2.ToArray();

      Console.WriteLine("Objects are Equal : {0}", b1.SequenceEqual(b2));

      Console.ReadKey();
    }
  }

  [Serializable]
  class Person
  {
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public List<Person> Children { get; private set; }

    public Person()
    {
      Children = new List<Person>();
    }
  }
}