То, что вы ищете, это выражения Linq.Вот пример построения вспомогательного выражения свойства в действии.
Использование этого класса
public class ExampleClass
{
public virtual string ExampleProperty
{
get;
set;
}
public virtual List<object> ExampleListProperty
{
get;
set;
}
}
Следующие тесты демонстрируют динамический доступ к его свойствам с помощью классов Linq.Expression.
[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 );
}
}
РЕДАКТИРОВАТЬ
Вы слишком далеко продвинулись с этим кодом.Этот код создает метод с нужной сигнатурой лямбды, а затем выполняет ее (.Invoke).Затем вы пытаетесь передать результат объекта (отсюда и ошибку компиляции) в настройку для Moq.Moq выполнит выполнение метода и подключит его, как только вы скажете ему, как действовать (отсюда и лямбда).Если вы используете созданное мной лямбда-выражение, оно создаст то, что вам нужно.
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'S CODE
instance.Setup(lambdaExpression).Returns(inMemoryTable);
Сделайте это вместо
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);
РЕДАКТИРОВАТЬ
Сделал попытку исправления GetMockContext.Пожалуйста, обратите внимание на несколько изменений (я пометил каждую строку).Я думаю, что это ближе.Мне интересно, наследует ли InMemoryTable от DataContext?Если нет, то подпись метода будет неправильной.
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?
}
Надеюсь, это поможет!