0

I am using EF Core non-entity model with get stored procedure calling. See below sample code

context.Query<ClassDTO>().FromSql("SpName @Param1, @Param2, @Param3", 
                                  new SqlParameter[] { param1, param2, param3 }).ToList();

Code is working fine. But I need to write mock test cases.

Can anyone help me out? How to mock Context.Query or how to write test cases for this code?

I tried to implement the follow way:

https://nodogmablog.bryanhogan.net/2017/11/unit-testing-entity-framework-core-stored-procedures/

But it will work for ** productContext.Products.MockFromSql(...)

But for me It is Like productContext.Query.MockFromSql(). So advice me how to write test cases.

Thanks in advance.

A Siva

4
  • I'm voting to close this question as off-topic because this question primarily focused on seeking coding services without any evidence of doing anything themselves. SO is not a coding service Commented May 10, 2019 at 5:36
  • 1
    Don't mock FromSql and DbContext in general. Write and execute tests against actual database. Mocking will provide zero value and waste the time. Commented May 10, 2019 at 6:06
  • 1
    If I try to execute test against actual database. I am getting the following expection. (This overload of the method 'Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSql' is currently not supported) Commented May 10, 2019 at 6:26
  • Are you using Repository Pattern? Commented May 12, 2019 at 14:45

1 Answer 1

2

The actual FromSql mock set up for a DbQuery<TQuery> is the same as a DbSet<TEntity> so the OP link is relevant (although it's a catch all implementation, if you need to match on the FromSql sql/parameters you'll need to do additional mock set up; warning: it gets ugly quickly).

You need to mock the DbQuery<TQuery> with a queryable sequence, mock the query provider as per the OP link (extended with any specific mock matching that you need) and then assign the DbQuery mocked object to BOTH the DbContext .Query<TQuery>() method and the DbContext DbQuery<TQuery> property.

In terms of mocking a DbQuery, this is what I use to create one:

public static Mock<DbQuery<TQuery>> CreateDbQueryMock<TQuery>(this DbQuery<TQuery> dbQuery, IEnumerable<TQuery> sequence) where TQuery : class {
    var dbQueryMock = new Mock<DbQuery<TQuery>>();

    var queryableSequence = sequence.AsQueryable();

    dbQueryMock.As<IAsyncEnumerableAccessor<TQuery>>().Setup(m => m.AsyncEnumerable).Returns(queryableSequence.ToAsyncEnumerable);
    dbQueryMock.As<IQueryable<TQuery>>().Setup(m => m.ElementType).Returns(queryableSequence.ElementType);
    dbQueryMock.As<IQueryable<TQuery>>().Setup(m => m.Expression).Returns(queryableSequence.Expression);
    dbQueryMock.As<IEnumerable>().Setup(m => m.GetEnumerator()).Returns(queryableSequence.GetEnumerator());
    dbQueryMock.As<IEnumerable<TQuery>>().Setup(m => m.GetEnumerator()).Returns(queryableSequence.GetEnumerator()); 
    dbQueryMock.As<IQueryable<TQuery>>().Setup(m => m.Provider).Returns(queryableSequence.Provider);

    return dbQueryMock;
}

Then if I need to support FromSql I change the provider to a query provider mock (as per the OP the mock set up for CreateQuery):

mock.As<IQueryable<TEntity>>().Setup(m => m.Provider).Returns(queryProviderMock.Object);

I ended up wrapping the above in a library if you want to save yourself some time: https://github.com/rgvlee/EntityFrameworkCore.Testing

Sign up to request clarification or add additional context in comments.

3 Comments

I wouldn't mind knowing what the down vote is for. For the efcore version at the time of writing, the advice provided is accurate.
I use an EF Core 3.1.6 and there is no such thing like an IAsyncEnumerableAccessor which you used in the 5th line.
The OP and my answer is for EFCore 2, which supported FromSql. The complete mock set up for a query/read only set is a lot more involved (keep in mind that my answer is meant to be aggregated with the link in the OP as well).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.