Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I've been able to mock DbSet's from entity framework with Moq using this link.

However, I would now like to know how I could mock the call to SqlQuery. Not sure if this is possible or how as it relies on the mocked db context knowing what "query" is being called.

Below is what I am trying to mock.

var myObjects = DbContext.Database
    .SqlQuery<MyObject>("exec [dbo].[my_sproc] {0}", "some_value")
    .ToList();

I currently haven't tried anything as did not know how to start mocking this example.

The mocking of the DbSet is below and to re-iterate, I can correctly mock returning a DbSet of MyObject's but now am trying to mock a SqlQuery that returns a list of MyObject's.

var dbContext = new Mock<MyDbContext>();
dbContext.Setup(m => m.MyObjects).Returns(mockObjects.Object);

dbContext.Setup(m => m.Database.SqlQuery... something along these lines
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
625 views
Welcome To Ask or Share your Answers For Others

1 Answer

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);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...