Database.SqlQuery<T>
is not marked as virtual, but Set<T>.SqlQuery
is marked as virtual.
Based on Database.SqlQuery<T>
documentation
The results of this query are never tracked by the context even if the
type of object returned is an entity type. Use the 'SqlQuery(String,
Object[])' method to return entities that are tracked by the
context.
and Set<T>.SqlQuery
documentation
By default, the entities returned are tracked by the context; this can
be changed by calling AsNoTracking on the DbRawSqlQuery returned.
then the Database.SqlQuery<T>(String, Object[])
should be equivalent with Set<T>.SqlQuery(String, Object[]).AsNoTracking()
(only if T
is EF entity, not a DTO / VM).
So if you can replace the implementation into:
var myObjects = DbContext
.Set<MyObject>()
.SqlQuery("exec [dbo].[my_sproc] {0}", "some_value")
.AsNoTracking()
.ToList();
you can mock it as follow
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);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…