Mocking EF6 database context

c# entity-framework entity-framework-6 unit-testing

Question

I have a lot of instantiations of the DB context in my methods, like:

using (myEntities context = new myEnties())
    [do something with the context...]
}

I learn now, that my code is legacy code because it is lacking unit tests. To make my code testable, I would need to inject the context somehow, maybe via the constructor of the class. I would then maybe use Effort.EF6 or something to mock the context.

However, first I have to get away from constructing the context locally. But here is my question: when I started with EF a long time ago, I learned that it was a very good idea to have a short living context (while in the good old ADO days one would think twice about releasing a connection once established). Is it really a good idea to store the context in a field and not release it at all (a practice I saw even in MS code examples)? Does it release itself and "using" is not required?

On a side note: I could alternatively use integration tests and just provide the original connection and set up test data etc. I would then not need to refactor hundreds of "using" statements. This of course would slow the tests but it would also test my database (I am using a lot of stored procedures). Is this a feasible approach then?

1
0
10/3/2017 8:26:23 PM

Accepted Answer

You can introduce a ContextFactory abstraction and keep hundreds of using statements and change only how context is initialized.

public interface IContextFactory
{
    DbContext Create();
}

And use it

using (var context = _contextFactory.Create())
{
    // Query staff
}

With approach above you will be able to provide mocked context to the code under the test or provide context connected to the test database for integration tests.

Suggest using some In-Memory database provider or SQLLite with in-memory mode for testing EF related logic as a black box. With context factory you will be able to pass required implementation of context to the code under the test.

1
10/4/2017 7:14:11 AM

Popular Answer

The easiest method I find to introduce unit testing to EF-related code that can be rolled out incrementally is to use a repository pattern. Often when you see examples of repositories you will see generic implementations, I.e. a repository per entity providing CRUD operations. Instead I favour using a repository per business area, think something along the lines of a repository per controller. (Not that specifically, but rather a repository serves a distinct area of the domain.) The repositories are responsible for: Creating entities, Retrieving entities, and in the case of hard-deletes, Deleting entities. To get repositories to play nice with each other, and other code using DB Contexts you should also consider a unit of work pattern to wrap code in your controllers or service layer classes that will be interacting with a DbContext and Repositories. A really nice one I use regularly for EF is Mehdime DBContextScope.

With a unit of work like the DBContextScope, the repositories themselves are kept very lightweight where any method to retrieve data returns IQueryable<TEntity>, including when expected to be retrieving a single entity. Create methods are responsible for ensuring that code is passing all required data/references, and Delete methods ensure that EF cleans up orphaned records where needed. By returning IQueryable you can avoid moving a lot of selection logic or decisions about what data to return into the repository as the calling code can do things like: .Include(), .Select(), .Any(), .Count(), etc. as appropriate to ensure that with deferred execution the queries executed are quite optimal.

This approach can be implemented alongside code using DbContexts, and the Repository implementations are easily mocked out. (I.e. return a list of stub entities, etc.)



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow