我正在尝试遵循Microsoft 为单元测试 DbSets提供的http://msdn.microsoft.com/en-us/library/dn314429.aspx指南。一切进展顺利——正如他们所记录的那样。直到我得到一些适用于继承表的代码。由于 OfType() 是一种扩展方法,我无法弄清楚如何创建一个 Mock 来保持我的代码可测试。
澄清一下:我正在尝试测试我的服务层,它采用一个注入的 DBContext,它公开了几个 DbSet。特别是,我有一个抽象的 History 类,它具有 StaffHistory、ContactHistory 等的具体派生类型。因此,我的 Dbcontext 上只有 1 个 DbSet,它是 History 类型。然后我使用扩展方法 OfType 设置鉴别器并查询特定类型。
当我创建一个 Mock DbSet 时,通常一切正常,除了 OfType 扩展方法失败,报告 NullReference 异常。
有什么想法或提示吗?
服务层:
public IEnumerable<ContactHistory> GetContactHistory(int ContactId, int AgeInDays)
{
var age = DateTimeOffset.Now.AddDays(-Math.Abs(AgeInDays));
return context.History.OfType<ContactHistory>()
.Where(h => h.ContactId == ContactId && h.CreatedAt >= age)
.AsEnumerable();
}
单元测试代码:
[TestMethod]
public void History_Returns_Limited_Results()
{
var testData = new List<ContactHistory> {
new ContactHistory {
ContactId = 1,
CreatedAt = DateTimeOffset.Now,
UserName = "UserA",
Action = "Action",
},
new ContactHistory {
ContactId = 4,
CreatedAt = DateTimeOffset.Now.AddDays(-61),
UserName = "UserA",
Action = "Action",
},
new ContactHistory {
ContactId = 4,
CreatedAt = DateTimeOffset.Now.AddDays(-60),
UserName = "UserA",
Action = "Action",
},
new ContactHistory {
ContactId = 4,
CreatedAt = DateTimeOffset.Now,
UserName = "UserA",
Action = "Action",
}
}.AsQueryable();
// Setup
var mockContext = new Mock<IPEContext>();
var mockSet = new Mock<IDbSet<History>>();
mockSet.As<IQueryable<ContactHistory>>().Setup(m => m.Provider).Returns(testData.Provider);
mockSet.As<IQueryable<ContactHistory>>().Setup(m => m.Expression).Returns(testData.Expression);
mockSet.As<IQueryable<ContactHistory>>().Setup(m => m.ElementType).Returns(testData.ElementType);
mockSet.As<IQueryable<ContactHistory>>().Setup(m => m.GetEnumerator()).Returns(testData.GetEnumerator());
mockContext.Setup(c => c.History).Returns(mockSet.Object);
// Test
var service = new HistoryService(mockContext.Object);
var historyFound = service.GetContactHistory(4, 60);
// Verify
Assert.IsNotNull(historyFound);
Assert.AreEqual(2, historyFound.Count());
}
我的方法有什么缺陷吗?我设置模拟的方式有什么缺陷吗?这是遵循我上面提到的 Microsoft 文章,以便我可以测试作用于 DbSet 的服务逻辑。唯一的缺陷似乎是扩展方法——不知道我应该如何解决这个问题。