Entity Framework has an InMemory provider that is useful when you want to test functionality using something that approximates connecting to a real database in your Unit Tests.
I prefer to leave database testing to the Integration Test layer and mock the Entity Framework context in my unit tests. Recently I was building a demo for a client and I wanted to mock the Entity Framework context. In researching different methods of achieving my goal, I came across MockQueryable by Roman Titov.
As per the ReadMe file on the GitHub page:
“Extensions for mocking Entity Framework Core (EFCore) operations such ToListAsync, FirstOrDefaultAsync etc. by Moq, NSubstitute or FakeItEasy When writing tests for your application it is often desirable to avoid hitting the database. The extensions allow you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data.”
Let’s start the example with Jason Taylor’s Clean Architecture template as a baseline for this post. If you are interested in Clean Architecture and are looking for a solid template to start your next project I highly recommend watching the following YouTube video:
To install the template:
- Install the latest .NET Core SDK
- Create a folder for the new code and navigate to it.
- Run dotnet new –install Clean.Architecture.Solution.Template to install the project template
- Run dotnet new ca-sln to create a new project
- Navigate to src/WebUI and run dotnet run to launch the project
- Once the project compiles and runs shut it down using ctrl + c from the resulting command line window.
Under the folder tests/Application.UnitTests/TodoLists/Queries there is a test file named GetTodosQueryTests.cs. Now let’s use MockQueryable to remove the dependency of Entity Framework InMemory for this test.
- Install MockQueryable via Nuget into the project Application.UnitTests. My personal preference for mock frameworks is Moq – which conveniently is the mock framework used by the template. This can be done from the package manager console. Please ensure that the default project points at tests\Application.UnitTests
- The code for GetTodosQueryTests before changes
- Remove the setting of the _context field from the constructor
- Add a mocked IApplicationDbContext variable and instantiate
- Create a list of known TodoList objects
- Create the mocked DbSet of TodoListItems and setup the mocked IApplicationDbContext to return the mocked TodoListItem
- Use the mocked IApplicationDbContext in the GetTodosQueryHandler.
- The code for GetTodosQueryTests after changes
The code for this blog post is located here