2

So, I have a layer in my application that maps one type of an object into another. Think ViewModel to model type of mapping. The ViewModel may have properties that are named differently or do not exist in the model. And vice-versa will be true as well.

I want to test my mapping layer, comparing the assignments, but also allowing me to provide some sort edge case handling for the properties that are different. Ideally, the test would fail if all of the properties in the ViewModel are not checked.

Does anyone know if such a beast exists already?

public class CustomerViewModel
{
     // This is the same as CustomerModel.CustomerName, but the names differ
     public string Name { get; set; }
     public int ID { get; set; }
}

public class CustomerModel
{
     public string CustomerName { get; set; }
     public int ID { get; set; }
}

// Would auto test the properties that match automatically.  Additionaltest test for non matching.  Fails if all properties aren't tested
Assert.CompareObjects(customerViewModelInstance, customerModelInstance)
     .AdditionalTest("Name", "CustomerName")
     .AdditionalComplexText((viewModel, model) =>
           {
                // do some sort of a compare of complex objects.  Maybe the viewmodel has address fields, address1, address2 while the Model has an Address object with those fields.
           });

The driving force behind this is the daunting task of having to assert every single property manually in code for a very large application.

Brian
  • 5,069
  • 7
  • 37
  • 47
Darthg8r
  • 12,377
  • 15
  • 63
  • 100
  • How would "such a beast" know which properties you're comparing to which other properties? Outside of that, I'd think the most you could do in an automated fashion is to compare the *number* of properties between each class to make sure they're equal; but that wouldn't prove that all the assignments existed. – Ryan Lundy Jan 24 '13 at 18:31
  • @Kyralessa. Please see my answer. There are definitely ways to compare the actual properties. – David L Jan 24 '13 at 18:33
  • @DavidL, did you notice that the names may differ between the two classes? – Ryan Lundy Jan 24 '13 at 19:28
  • @Kyralessa I did not. Excellent point and my apologies for missing this. – David L Jan 24 '13 at 19:31
  • Kyralessa, look at the assert statement at the end. The idea was to have additional tests for properties whose names and types do not match. See "AdditionalTest" and "AdditionalComplexTest" – Darthg8r Jan 24 '13 at 20:07

1 Answers1

2

You would need to override .Equals() so that it compared properties, then use the

Assert.AreEqual Method (Object, Object). Please see below:

Compare equality between two objects in NUnit

You would want to implement such a thing in your model itself.

// useful class
public class MyStuff 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MyValue { get; set; }

    public override int GetHashCode()
    {
        return Id;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (MyStuff)) return false;

        var other = obj as MyStuff;

        return (other.Id == Id
            && other.MyValue == MyValue
            && other.Equals(other.Name, Name));
        // use .Equals() here to compare objects; == for Value types

        // alternative weak Equals() for value objects:
        // return (other.MyValue == MyValue && other.Equals(other.Name, Name) );
    }
}

EDIT: In retrospect, I have decided that having a duplication of properties in your viewmodel and model is probably a bad pattern and is part of the reason you are having so many testing issues. Rather, you should allow your ViewModel to wrap your model.

public class CustomerViewModel
{
    // This is the same as CustomerModel.CustomerName, but the names differ
    public CustomerModel CustomerModel { get; set; }

    pubiic CustomerViewModel()
    {
        CustomerModel = new CustomerModel();
    }
}

public class CustomerModel
{
     public string CustomerName { get; set; }
     public int ID { get; set; }
}

At that point it's much easier to test it since you have your wrapped model that you can compare to a new copy of the same model, using the .Equals override pattern. At the end of the day I just don't think that trying to come up with a magic bullet "compare any model to any model" is a good idea, nor is it practical.

Community
  • 1
  • 1
David L
  • 32,885
  • 8
  • 62
  • 93
  • As a side note overriding equals can cause some headaches later on. Unless you need to utilize the `Equals` method I would advise creating a new method `CustomEquals` method and call on that so that you still have the ability to tell if 2 objects are exact duplicates. – Anthony Nichols Jan 24 '13 at 18:44
  • A simple override of equals is a bad idea in this case. I should not have to change a class and tightly couple one type to another just to support unit testing. The comparison needs to be outside of the classes themselves. – Darthg8r Jan 24 '13 at 20:09
  • @Darthg8r I understand your concern. That said, I am not sure how this beast of yours would be built in light of your requirements. Would you take two classes, pull out all properties, then match underlying types and then compare? How would you be certain you were comparing the correct properties if the names are different? I'm not sure how this could be pulled off. It is starting to look like you may have to do a manual comparison. – David L Jan 24 '13 at 20:16
  • @Darthg8r In retrospect, I suppose you could build some class with input parameters for class names and property names. It could then peek into each and pull out those properties and their values and then compare them and return a bool. That would do it. – David L Jan 24 '13 at 20:34
  • @Darthg8r I've been thinking a lot about a PoC that would do what you're looking for. I have some concerns/questions though. What would you do if they didn't have identical number and type of properties? Would that be a failed validation? – David L Jan 24 '13 at 23:47