Рекурсивно проверять свойства объекта и сравнивать свойство двух объектов по свойству - PullRequest
0 голосов
/ 07 июля 2019

Недавно я написал простой метод для класса, который выполняет DeepCopy всех свойств и возвращает новое свойство. Ниже приведены три примера классов и метод DeepCopy:

class Person
{
    public int Age {get; set;}
    public string Name {get; set;}
    Public Address address {get; set;}
    public List<Person> Children {get; set;}
}

class Address
{
    public string StreetAddress {get; set;}
    public int ZipCode {get; set; }
    public Region region {get; set;}    
}

class Region
{
    public string City {get; set;}
    public string Country {get; set;}
}

public static Person DeepCopy(this Person p)
{
    return new Person
    {
        Age = p.Age,
        Name = p.Name,
        Address = p.Address,
        Children = p.Children
    }
}

Я хочу написать модульные тесты, чтобы проверить:

  1. Все свойства исходного объекта копируются во второй объект, и значения идентичны.
  2. Используя отражение, рекурсивно получите список свойств (поскольку каждый объект может иметь свойство другого типа, которое само имеет свойство ...) и убедитесь, что метод DeepCopy копирует все свойства. Причиной этого теста является сбой, если новое свойство добавлено в класс Person и не скопировано в новый объект в методе DeepCopy.

Я уже пытался использовать отражение, чтобы получить все свойства, но одна из проблем, с которыми я столкнулся, в какой-то момент застревает в цикле.

Ответы [ 3 ]

0 голосов
/ 07 июля 2019

Как сказал @Backs, FluentAssertions - это то, что вам нужно здесь:

Чтобы утверждать, что два объекта равны (через их реализацию Object.Equals), используйте

string otherObject = "whatever";
theObject.Should().Be(otherObject, "because they have the same values");
theObject.Should().NotBe(otherObject);

0 голосов
/ 09 июля 2019

Попробуйте это:

// Taken from: https://gist.github.com/jonathanconway/3330614
public static bool IsSimpleType(this Type type)
{
    return
      type.IsValueType ||
      type.IsPrimitive ||
      new Type[] {
        typeof(String),
        typeof(Decimal),
        typeof(DateTime),
        typeof(DateTimeOffset),
        typeof(TimeSpan),
        typeof(Guid)
      }.Contains(type) ||
      Convert.GetTypeCode(type) != TypeCode.Object;
}

public static bool CompareIEnumerable(IEnumerable enumerable1, IEnumerable enumerable2)
{
    var obj1Iterator = enumerable1.GetEnumerator();
    var obj2Iterator = enumerable2.GetEnumerator();
    bool has1 = obj1Iterator.MoveNext(), has2 = obj2Iterator.MoveNext();

    //loop through the enumerables
    while (has1 && has2)
    {
        //compare the values deeply
        if (!DeepCompare(obj1Iterator.Current, obj2Iterator.Current))
        {
            return false;
        }

        has1 = obj1Iterator.MoveNext();
        has2 = obj2Iterator.MoveNext();
    }

    // if the loop terminated and has1 != has2, one of them have more items, the are not equal
    return has1 == has2;
}

public static bool DeepEquals<T>(this T obj1, T obj2)
{
    //if one is null and the other is not, they are not equal
    if (obj1 != null ^ obj2 != null)
    {
        return false;
    }
    //else if both are null, they are equal
    else if (obj1 == null && obj2 == null)
    {
        return true;
    }

    Type objectsType = obj1.GetType();

    //if they are a simple type, compare them using .Equals method
    if (objectsType.IsSimpleType())
    {
        return obj1.Equals(obj2);
    }
    //if they are IEnumerable type, compare them using CompareIEnumerable method
    else if (objectsType.GetInterface("IEnumerable") != null)
    {
        return CompareIEnumerable((IEnumerable)obj1, (IEnumerable)obj2);
    }

    //The type is not simple nor IEnumerable, loop through the properties and check if they are equal (Deeply)
    foreach (var member in objectsType.GetMembers().Where(m => m.MemberType.Equals(MemberTypes.Field) || m.MemberType.Equals(MemberTypes.Property)))
    {
        Type t = member.MemberType.Equals(MemberTypes.Field) ?
          ((FieldInfo)member).FieldType :
          ((PropertyInfo)member).PropertyType;
        Func<object, object> getter = member.MemberType.Equals(MemberTypes.Field) ?
          new Func<object, object>(((FieldInfo)member).GetValue) :
          new Func<object, object>(((PropertyInfo)member).GetValue);

        if (!DeepCompare(getter(obj1), getter(obj2)))
        {
            return false;
        }
    }

    return true;
}
0 голосов
/ 07 июля 2019

Для модульных тестов есть lib FluentAssetions :

string username = "dennis";
username.Should().Be("jonas");

Ожидаемое имя пользователя: «jonas», но «dennis» отличается рядом с «d» (индекс 0).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...