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

发布于 2024-08-28 17:37:43 字数 961 浏览 8 评论 0原文

为了实现这一点(但未能做到),我反映了预期对象和实际对象的属性,并确保它们的值相等。只要它们的属性是单个对象,即不是列表、数组、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,这在Turn 要求我知道列出的类型,但我不(想要)。
它还要求我知道哪些属性是列表类型,但我不知道如何知道。

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

注意:我特别不想要求它们相等,因为一个来自我的测试对象,一个是在我的测试类中构建的,以便与某些东西进行比较。

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 would 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猫瑾少女 2024-09-04 17:37:43

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

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

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>();
    }
  }
}
睫毛溺水了 2024-09-04 17:37:43

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

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

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 })
            );              
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文