开发者

How do I assert that two arbitrary type objects are equivalent, without requiring them to be equal?

To accomplish this (but failing to do so) I'm reflecting over properties of an expected and actual object and making sure their values are equal. This works as expected as long as their properties are single objects, i.e. not lists, arrays, IEnumerable... If the property is a list of some sort, the test fails (on the Assert.AreEqual(...) inside the for loop).

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);
    }
}

If dealing with a list property, I w开发者_高级运维ould get the expected results if I instead used CollectionAssert.AreEquivalent(...) but that requires me to cast to ICollection, which in turn requries me to know the type listed, which I don't (want to).

It also requires me to know which properties are list types, which I don't know how to.

So, how should I assert that two objects of an arbitrary type are equivalent?

Note: I specifically don't want to require them to be equal, since one comes from my tested object and one is built in my test class to have something to compare with.


Not sure this will go down well, but one option would be to serialize the objects to a byte array and compare them. Of course this assumes that the objects you are dealing with are serializable.

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>();
    }
  }
}


This works, not something I would really recommend but it works.

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 })
            );              
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜