Как я могу утверждать, что два объекта произвольного типа эквивалентны, не требуя, чтобы они были равны? - PullRequest
0 голосов
/ 12 апреля 2010

Для этого (но не в состоянии) я размышляю над свойствами ожидаемого и фактического объекта и проверяю, чтобы их значения были равны. Это работает, как и ожидалось, если их свойства являются единичными объектами, то есть не списками, массивами, 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 ]

1 голос
/ 12 апреля 2010

Не уверен, что все пойдет хорошо, но одним из вариантов будет сериализация объектов в байтовый массив и сравнение их. Конечно, предполагает , что объекты, с которыми вы имеете дело, являются сериализуемыми.

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>();
    }
  }
}
1 голос
/ 12 апреля 2010

Это работает, я бы не советовал, но это работает.

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