在entity framework6.1中模拟DbContext
我发现了一些例子(显然)显示了用EF 6模拟DbContext的明显工作示例,然而,它们似乎都不适合我,我不完全确定原因。
这是我设置模拟的unit testing代码;
var mockData = new List { new User { Email = "my@email.com", Id = 1 } }.AsQueryable(); var mockSet = new Mock<DbSet>(); mockSet.As<IQueryable>().Setup(m => m.Provider).Returns(mockData.Provider); mockSet.As<IQueryable>().Setup(m => m.Expression).Returns(mockData.Expression); mockSet.As<IQueryable>().Setup(m => m.ElementType).Returns(mockData.ElementType); mockSet.As<IQueryable>().Setup(m => m.GetEnumerator()).Returns(mockData.GetEnumerator()); var mockContext = new Mock(); mockContext.Setup(c => c.Users).Returns(mockSet.Object);
然后调用我正在测试的服务;
var service = new UsersService(mockContext.Object); var user = service.GetById(1);
这会抛出NullReferenceException,因为底层DbSet始终为null。 代码执行以下操作;
在BaseClass;
public IEnumerable GetAll() { return _dbSet.AsEnumerable(); }
在子类中;
public User GetById(int id) { return GetAll().FirstOrDefault(x => x.Id == id); }
请注意,尽管SO上还有其他与之相关的问题,但它们不包括EF 6。
作为参考,这是一篇MSDN文章,相同的代码带有修改以使其编译。
https://msdn.microsoft.com/en-us/data/dn314429.aspx
编辑:
降低UserService(它使用generics/接口)的复杂性,现在代码简单;
public User GetById(int id) { return _dbContext.Set().FirstOrDefault(x => x.Id == id); }
如果我进一步改变这个;
var dbSet = _dbContext.Set(); return dbSet.FirstOrDefault(x => x.Id == id);
我可以清楚地看到dbSet为null。
编辑2
根据wablab的建议,似乎mock .Set解决了这个问题。
同样感谢Vladyslav Kushnir的DbSet通用方法。
为可能需要它的任何人提供此代码的工作代码;
private static Mock<DbSet> GetDbSetMock(IEnumerable items = null) where T : class { if (items == null) { items = new T[0]; } var dbSetMock = new Mock<DbSet>(); var q = dbSetMock.As<IQueryable>(); q.Setup(x => x.GetEnumerator()).Returns(items.GetEnumerator); return dbSetMock; } var mockContext = new Mock(); var users = new List { new User { Email = "my@email.com", Id = 1 } }; mockContext.Setup(x => x.Set()).Returns(GetDbSetMock(users).Object); var service = new UsersService(mockContext.Object); var user = service.GetById(1);
我想你需要在Set
方法上创建一个设置来返回你的mock。
private Mock> GetDbSetMock(IEnumerable items = null) where T : class { if (items == null) { items = new T[0]; } var dbSetMock = new Mock>(); var q = dbSetMock.As>(); q.Setup(x => x.GetEnumerator()).Returns(items.GetEnumerator); return dbSetMock; }
这是我用来模拟DbContext的DbSet的非常好的通用方法。 这种方法的实际调用是:
var contextMock = new Mock(); contextMock.Setup(x => x.MyDbEntities).Returns(GetDbSetMock().Object);