0

Please see the code below:

public static class AssertEx
{
    public static void PropertyValuesAreEquals(object actual, object expected)
    {
        PropertyInfo[] properties = expected.GetType().GetProperties();
        foreach (PropertyInfo property in properties)
        {
            object expectedValue = property.GetValue(expected, null);
            object actualValue = property.GetValue(actual, null);

            if (actualValue is IList)
                AssertListsAreEquals(property, (IList)actualValue, (IList)expectedValue);
            else if (!Equals(expectedValue, actualValue))
                Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
        }
    }

    private static void AssertListsAreEquals(PropertyInfo property, IList actualList, IList expectedList)
    {
        if (actualList.Count != expectedList.Count)
            Assert.Fail("Property {0}.{1} does not match. Expected IList containing {2} elements but was IList containing {3} elements", property.PropertyType.Name, property.Name, expectedList.Count, actualList.Count);

        for (int i = 0; i < actualList.Count; i++)
            if (!Equals(actualList[i], expectedList[i]))
                Assert.Fail("Property {0}.{1} does not match. Expected IList with element {1} equals to {2} but was IList with element {1} equals to {3}", property.PropertyType.Name, property.Name, expectedList[i], actualList[i]);
    }
}

I took this from here: Compare equality between two objects in NUnit (Juanmas' answer)

Say I have an interface like this:

public interface IView
{
    decimal ID { get; set; }
    decimal Name { get; set; }
}

I then have two views like this:

IView view = new FormMain();
IView view2 = new FormMain();

view and view2 are then given properties.

I then want to compare the interfaces so I do this:

Assert.AreEqual(Helper.PropertyValuesAreEquals(view, view2), true);

However, this produces an exception:

"Property Get method was not found.".

How can I ensure this function only gets properties for the properties in my interface?

Should I even be unit testing a view like this?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
w0051977
  • 15,099
  • 32
  • 152
  • 329
  • You could consider using Generics, also in the logic above you should check if property exists in both objects provided. – Nkosi May 26 '17 at 11:39

3 Answers3

0

The Property Get method was not found. error occurs when you have property with only setter, e.g. int MyProperty { set { x = value; } }.

So you need to just skip these properties in your PropertyValuesAreEquals method.

If you want to check only properties that belongs to specific interface, you must change your method to something like this:

public static void PropertyValuesAreEquals<T> (T actual, T expected)
{
     PropertyInfo[] properties = typeof (T).GetProperties ();
     //...
}

Now we can run this method: PropertyValuesAreEquals<IView> (view, view2);

Don't forget about <IView> parameter; otherwise compiler may use FormMain type as a generic type parameter.

apocalypse
  • 5,764
  • 9
  • 47
  • 95
0

You could consider using Generics, also in the logic above you should check if property exists in both objects provided and can be read.

public static void PropertyValuesAreEquals<T>(T actual, T expected) 
    where T : class {
    var properties = typeof(T).GetProperties().Where(p => p.CanRead);
    foreach (var property in properties) {
        var expectedValue = property.GetValue(expected, null);
        var actualValue = property.GetValue(actual, null);

        if (actualValue is IList)
            AssertListsAreEquals(property, (IList)actualValue, (IList)expectedValue);
        else if (!Equals(expectedValue, actualValue))
            Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
    }
}

And used in your case as

Assert.IsTrue(Helper.PropertyValuesAreEquals<IView>(view, view2));
Nkosi
  • 235,767
  • 35
  • 427
  • 472
0

You can also use a generic function without specifying of type for "actual" and "expected".

public static void PropertyValuesAreEquals<T>(object actual, object expected)
{
    Assert.IsTrue(actual is T);
    Assert.IsTrue(expected is T);

    foreach (var property in typeof(T).GetProperties().Where(o => o.CanRead))
    {
        var actualValue = property.GetValue(actual, null);
        var expectedValue = property.GetValue(expected, null);

        ...
    }
}
Georg
  • 1,946
  • 26
  • 18