Dynamic Moq Setup () call at runtime

I want to create a factory that will create cheated objects for my unit tests. I have already managed to set up my tests so that I can mock Linq2Sql DataContext and return the table in memory instead of hitting the database. I configured it like this:

_contactsTable = new InMemoryTable<Contact>(new List<Contact>()); _contactEmailsTable = new InMemoryTable<ContactEmail>(new List<ContactEmail>()); // repeat this for each table in the ContactsDataContext var mockContext = new Mock<ContactsDataContext>(); mockContext.Setup(c => c.Contacts).Returns(_contactsTable); mockContext.Setup(c => c.ContactEmails).Returns(_contactEmailsTable); // repeat this for each table in the ContactsDataContext 

This is tedious if the DataContext contains many tables, so I thought that a simple factory method that used reflection to get all the tables outside the DataContext could help:

 public static DataContext GetMockContext(Type contextType) { var instance = new Mock<DataContext>(); var propertyInfos = contextType.GetProperties(); foreach (var table in propertyInfos) { //I'm only worried about ITable<> now, otherwise skip it if ((!table.PropertyType.IsGenericType) || table.PropertyType.GetGenericTypeDefinition() != typeof (ITable<>)) continue; //Determine the generic type of the ITable<> var TableType = GetTableType(table); //Create a List<T> of that type var emptyList = CreateGeneric(typeof (List<>), TableType); //Create my InMemoryTable<T> of that type var inMemoryTable = CreateGeneric(typeof (InMemoryTable<>), TableType, emptyList); //NOW SETUP MOCK TO RETURN THAT TABLE //How do I call instance.Setup(i=>i.THEPROPERTYNAME).Returns(inMemoryTable) ?? } return instance.Object; } 

So far, I have figured out how to create objects that I need to configure for Mock, but I just can't figure out how to dynamically call Moq Setup (), passing property names. I started looking at the Invoke () Moq Setup () method, but it got really ugly.

Does anyone have an easy way to dynamically call Setup () and Returns () as follows?

Edit : Brian replied that I was there. Here's how it works:

 public static DataContext GetMockContext<T>() where T: DataContext { Type contextType = typeof (T); var instance = new Mock<T>(); var propertyInfos = contextType.GetProperties(); foreach (var table in propertyInfos) { //I'm only worried about ITable<> now, otherwise skip it if ((!table.PropertyType.IsGenericType) || table.PropertyType.GetGenericTypeDefinition() != typeof(ITable<>)) continue; //Determine the generic type of the ITable<> var TableType = GetTableType(table); //Create a List<T> of that type var emptyList = CreateGeneric(typeof(List<>), TableType); //Create my InMemoryTable<T> of that type var inMemoryTable = CreateGeneric(typeof(InMemoryTable<>), TableType, emptyList); //NOW SETUP MOCK TO RETURN THAT TABLE var parameter = Expression.Parameter(contextType); var body = Expression.PropertyOrField(parameter, table.Name); var lambdaExpression = Expression.Lambda<Func<T, object>>(body, parameter); instance.Setup(lambdaExpression).Returns(inMemoryTable); } return instance.Object; } 
+4
source share
1 answer

What you are looking for are Linq expressions. Here's an example of creating a resource membership expression in action.

Using this class

 public class ExampleClass { public virtual string ExampleProperty { get; set; } public virtual List<object> ExampleListProperty { get; set; } } 

The following tests demonstrate dynamic access to these properties using the Linq.Expression classes.

 [TestClass] public class UnitTest1 { [TestMethod] public void SetupDynamicStringProperty() { var dynamicMock = new Mock<ExampleClass>(); //Class type var parameter = Expression.Parameter( typeof( ExampleClass ) ); //String rep of property var body = Expression.PropertyOrField( parameter, "ExampleProperty" ); //build the lambda for the setup method var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter ); dynamicMock.Setup( lambdaExpression ).Returns( "Works!" ); Assert.AreEqual( "Works!", dynamicMock.Object.ExampleProperty ); } [TestMethod] public void SetupDynamicListProperty_IntFirstInList() { var dynamicMock = new Mock<ExampleClass>(); var parameter = Expression.Parameter( typeof( ExampleClass ) ); var body = Expression.PropertyOrField( parameter, "ExampleListProperty" ); var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter ); var listOfItems = new List<object> { 1, "two", DateTime.MinValue }; dynamicMock.Setup( lambdaExpression ).Returns( listOfItems ); Assert.AreEqual( typeof( int ), dynamicMock.Object.ExampleListProperty[0].GetType() ); Assert.AreEqual( 1, dynamicMock.Object.ExampleListProperty[0] ); Assert.AreEqual( 3, dynamicMock.Object.ExampleListProperty.Count ); } [TestMethod] public void SetupDynamicListProperty_StringSecondInList() { var dynamicMock = new Mock<ExampleClass>(); var parameter = Expression.Parameter( typeof( ExampleClass ) ); var body = Expression.PropertyOrField( parameter, "ExampleListProperty" ); var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter ); var listOfItems = new List<object> { 1, "two" }; dynamicMock.Setup( lambdaExpression ).Returns( listOfItems ); Assert.AreEqual( typeof( string ), dynamicMock.Object.ExampleListProperty[1].GetType() ); Assert.AreEqual( "two", dynamicMock.Object.ExampleListProperty[1] ); Assert.AreEqual( 2, dynamicMock.Object.ExampleListProperty.Count ); } } 

EDIT

You take a step too far with this code. This code creates a method with the signature of the required lambda, and then executes it (.Invoke). Then you try to pass the result of the object (hence a compilation error) to the setting for Moq. Moq will execute the execution and connect to you as soon as you tell how to proceed (hence the lambda). If you use the lambda expression I created, it will build what you need.

 var funcType = typeof (Func<>).MakeGenericType(new Type[] {TableType, typeof(object)}); var lambdaMethod = typeof (Expression).GetMethod("Lambda"); var lambdaGenericMethod = lambdaMethod.MakeGenericMethod(funcType); var lambdaExpression = lambdaGenericMethod.Invoke(body, parameter); //var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>(body, parameter); // FOR REFERENCE FROM BRIAN CODE instance.Setup(lambdaExpression).Returns(inMemoryTable); 

Do it instead

 var parameter = Expression.Parameter( TableType ); var body = Expression.PropertyOrField( parameter, "PutYourPropertyHere" ); var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter ); instance.Setup(lambdaExpression).Returns(inMemoryTable); 

EDIT

Took a hit on GetMockContext fix. Pay attention to a few changes (I marked each line). I think this is closer. I am wondering if InMemoryTable inherits from DataContext? If not, the method signature will be incorrect.

 public static object GetMockContext<T>() where T: DataContext { Type contextType = typeof (T); var instance = new Mock<T>(); //Updated this line var propertyInfos = contextType.GetProperties(); foreach (var table in propertyInfos) { //I'm only worried about ITable<> now, otherwise skip it if ((!table.PropertyType.IsGenericType) || table.PropertyType.GetGenericTypeDefinition() != typeof(ITable<>)) continue; //Determine the generic type of the ITable<> var TableType = GetTableType(table); //Create a List<T> of that type var emptyList = CreateGeneric(typeof(List<>), TableType); //Create my InMemoryTable<T> of that type var inMemoryTable = CreateGeneric(typeof(InMemoryTable<>), TableType, emptyList); //NOW SETUP MOCK TO RETURN THAT TABLE var parameter = Expression.Parameter(contextType); var body = Expression.PropertyOrField(parameter, table.Name); var lambdaExpression = Expression.Lambda<Func<T, object>>(body, parameter); instance.Setup(lambdaExpression).Returns(inMemoryTable); } return instance.Object; //had to change the method signature because the inMemoryTable is not of type DataContext. Unless InMemoryTable inherits from DataContext? } 

Hope this helps!

+6
source

All Articles