I want to create a factory that will create commonly mocked objects for my unit tests. I’ve already managed to set up my tests so I can mock up a Linq2Sql DataContext and return an in memory table instead of hitting the database. I set it up 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 gets tedious if the DataContext contains a lot of tables, so I thought a simple factory method that used reflection to get all the tables off the DataContext might 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’ve figured out how to create the objects I need to setup for the Mock, but I just can’t figure out how to dynamically call Moq’s Setup() passing in the property names. I started looking at reflection to Invoke() Moq’s Setup() method, but it got really ugly fast.
Does anyone have a simple way to dynamically call Setup() and Returns() like this?
Edit: Brian’s answer got me 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;
}
What you are looking for are Linq Expressions. Here is a sample of building a property accessory expression in action.
Using this class:
The following tests demonstrate accessing its properties dynamically using the
Linq.Expressionclasses.EDIT
You are taking a step too far with this code. This code is creating a method with the signature of the lambda you want and then it’s executing it (.Invoke). You are then trying to pass the result of the object (hence the compile error) into the setup for Moq. Moq will do the method execution and hookup for you once you tell it how to act (hence the lambda). If you use the lambda expression creation that I provided, it will build what you need.
Do this instead
EDIT
Took a stab at correcting the GetMockContext. Please note the few changes (I marked each line). I think this is closer. I am wondering, does InMemoryTable inherit from DataContext? If not, the method signature will be incorrect.
I hope this helps!