我已经能够使用这个
link从Moq的实体框架中模拟DbSet.
但是,我现在想知道如何可以模拟对sqlQuery的调用.不知道这是可能的,还是如何依赖于嘲弄的数据库环境,知道正在调用什么“查询”.
下面是我试图嘲笑的.
var myObjects = DbContext.Database .sqlQuery<MyObject>("exec [dbo].[my_sproc] {0}","some_value") .ToList();
我目前没有尝试任何东西,因为不知道如何开始嘲笑这个例子.
DbSet的嘲笑在下面并重新迭代,我可以正确地模拟返回MyObject的DbSet,但现在我试图模拟一个返回MyObject列表的sqlQuery.
var dbContext = new Mock<MyDbContext>(); dbContext.Setup(m => m.MyObjects).Returns(mockObjects.Object); dbContext.Setup(m => m.Database.sqlQuery... something along these lines
解决方法
Database.SqlQuery<T>
未标记为虚拟,但
Set<T>.SqlQuery
被标记为虚拟.
The results of this query are never tracked by the context even if the
type of object returned is an entity type. Use the 07003 method to return entities that are tracked by the
context.
By default,the entities returned are tracked by the context; this can
be changed by calling AsNoTracking on the DbRawsqlQuery returned.
那么Database.sqlQuery< T>(String,Object [])应该与Set< T> .sqlQuery(String,Object [])等同.AsNoTracking()(只有当T是EF实体,而不是DTO / VM) .
所以如果你可以将实现替换成:
var myObjects = DbContext .Set<MyObject>() .sqlQuery("exec [dbo].[my_sproc] {0}","some_value") .AsNoTracking() .ToList();
你可以嘲笑它如下
var list = new[] { new MyObject { Property = "some_value" },new MyObject { Property = "some_value" },new MyObject { Property = "another_value" } }; var setMock = new Mock<DbSet<MyObject>>(); setMock.Setup(m => m.sqlQuery(It.IsAny<string>(),It.IsAny<object[]>())) .Returns<string,object[]>((sql,param) => { // Filters by property. var filteredList = param.Length == 1 ? list.Where(x => x.Property == param[0] as string) : list; var sqlQueryMock = new Mock<DbsqlQuery<MyObject>>(); sqlQueryMock.Setup(m => m.AsNoTracking()) .Returns(sqlQueryMock.Object); sqlQueryMock.Setup(m => m.GetEnumerator()) .Returns(filteredList.GetEnumerator()); return sqlQueryMock.Object; }); var contextMock = new Mock<MyDbContext>(); contextMock.Setup(m => m.Set<MyObject>()).Returns(setMock.Object);