Share via


Useful Moq Extension Method

I have been working with ASP .NET MVC and I use the Moq mocking library to help test the code I write.   Often in ASP MVC anonymous objects are passed around as function arguments.  This is especially common in calls to RouteUrl.  Since I want to be able to test this and verify that it is called correctly I wrote a handy extension method to make it easier called AsMatch.

To be able to test the UrlHelper (since it doesn't have an interface or virtual methods) I wrote a simple wrapper around it with an interface to enable testing.  Using that with this extension method makes testing route generation a breeze.

Given a call to generate a Url like this:

 var url = Url.RouteUrl("Show", new { projectName="matt" });

You can write a setup on your Mock of the Url helper using a similar syntax:

 UrlHelperMock
.Setup(x => x.RouteUrl("Show",new{ projectName="matt"}.AsMatch()))

.Return("someUrlToTest");

Here is the code that defines the AsMatch extension method:

     public static class ObjectMoqExtensions
    {
        public static object AsMatch(this object @object)
        {
            return Match<object>.Create(testObject => DoObjectsMatch(@object, testObject));
        }
        private static bool DoObjectsMatch(object object1, object object2)
        {
            var props1 = ToDictionary(object1);
            var props2 = ToDictionary(object2);
            var query = from prop1 in props1
                        join prop2 in props2 on prop1.Key equals prop2.Key
                        select prop1.Value.Equals(prop2.Value);
            return query.Count(x => x) == Math.Max(props1.Count(), props2.Count());
        }
        public static Dictionary<string, object> ToDictionary(object @object)
        {
            var dictionary = new Dictionary<string, object>();
            var properties = TypeDescriptor.GetProperties(@object);
            foreach (PropertyDescriptor property in properties)
                dictionary.Add(property.Name, property.GetValue(@object));
            return dictionary;
        }
    }