我想創建一個工廠,爲我的單元測試創建通常使用的模擬對象。我已經設置了我的測試,所以我可以模擬一個Linq2Sql DataContext並返回一個內存表而不是命中數據庫。我把它像這樣:在運行時動態調用Moq Setup()
_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
這得到乏味,如果在DataContext中含有大量的表,所以我想使用反射來得到一個簡單的工廠方法關閉DataContext的所有表可能會有所幫助:
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;
}
到目前爲止,我已經想出瞭如何創建我需要爲模擬設置的對象,但我無法弄清楚如何動態調用傳遞屬性名稱的Moq的Setup()方法。我開始考慮對Invoke()Moq的Setup()方法的反射,但它的速度真的很難看。
有沒有人有一個簡單的方法來動態調用這樣的Setup()和Returns()?
編輯:布賴恩的答案讓我在那裏。以下是它的工作方式:
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;
}
使用lambda方法的三條線正在製作一個方法,然後調用它。您需要在我的答案中使用示例創建lambda方法並傳遞給安裝方法。 –
感謝您的編輯。在您提到的具有特定上下文(ContactsDataContext)的第一部分代碼中,您希望將其遷移到使用通用上下文(DataContext)。這樣做的問題在於,您將DataContext的模擬與模板類上存在的屬性混合在一起。我將用更多的代碼更新我的答案。 –
啊,我想你的評論爲我排序。我需要在頂部創建一個模擬而不是模擬。有用! –