Introduction
In this post, we are going to have a look at how we can write automated tests using entity framework core.
As in the recent previous posts, the code can be found here.
The Story
A while back when working on a project, I wanted to do an integration test with a mock database so that I can validate that the database constraints are actually working and are configured properly.
So in my search to find a viable solution that will do the job but also won’t carry a lot of overhead in both processing power and cleanup, I ended up on this documentation page.
If you took a look at the documentation page, you will see that the documentation actually specifies two approaches for this.
So after having a look over both of them, I thought the InMemory approach would be better for me since I didn’t want to include an additional dependency to SQLite.
Well, soon after I followed the example and implemented it, I found out that it wasn’t in fact what I needed, mostly because of two major reasons:
- The InMemory database requires a name. The reason for this so that you can use the same database across tests. This was mostly an annoyance for me since I didn’t want to recreate the database in every test, and if I can help not repeating myself, all the better.
- The InMemory database is not a relational database, it’s not really much of a database at all since I found out the hard way that all the constraints I configured into my database context weren’t even validated. If I wasn’t following the Test Driven Development approach, I would have found out about a bug in my code when manually testing or worse, in production.
This brings me to this post’s topic, doing in memory testing using SQLite, reusing the functionality, and even inspecting the generated queries.
The Setup
First off, we will create a new ASP.NET Core MVC project with individual authentication (this is mostly because it comes already configured with a database context, of course, you can roll your own).
Next step, and where we will do most of the work, is the test project. For that, we will need a .NET Core Console project.
Once we have the test project and have referenced our WebApplication
project (so we can reach the DbContext
), we will need to install some Nuget packages:
Microsoft.NET.Test.Sdk
(15.7.2)
- This is needed to actually run the units tests.
NUnit
(3.10.1)
- My testing framework of choice, though you can use any framework that suits your needs.
NUnit3TestAdapter
(3.10)
- This is so that ReSharper and Visual Studio can find and run the tests.
Microsoft.AspNetCore.App
- Installing this package since we’re making use of the
IdentityDbContext
, though this is only because of the template I opted to use for this example.
Microsoft.EntityFrameworkCore.Sqlite
(2.1.0)
The Implementation
Now that we have all that we need, let’s move on to the implementation.
Out of habit, inside the test project, I usually create a folder called TestUtilities and inside that, a static
class called TestDatabaseContextFactory
.
I’ve annotated the class line by line to explain what everything does.
namespace Test.TestUtilities
{
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using WebApplication.Data;
public static class TestDatabaseContextFactory
{
public static ApplicationDbContext CreateDbContext()
{
DbContextOptionsBuilder<ApplicationDbContext>
contextOptionsBuilder =
new DbContextOptionsBuilder<ApplicationDbContext>();
LoggerFactory loggerFactory = new LoggerFactory();
loggerFactory
.AddDebug()
.AddConsole();
SqliteConnectionStringBuilder connectionStringBuilder =
new SqliteConnectionStringBuilder { Mode = SqliteOpenMode.Memory };
SqliteConnection connection =
new SqliteConnection(connectionStringBuilder.ConnectionString);
connection.Open();
contextOptionsBuilder.UseLoggerFactory(loggerFactory);
contextOptionsBuilder.UseSqlite(connection);
contextOptionsBuilder.EnableSensitiveDataLogging();
ApplicationDbContext context =
new ApplicationDbContext(contextOptionsBuilder.Options);
context.Database.EnsureCreated();
return context;
}
}
}
With this in place, we can now actually use it in our tests like so:
namespace Test
{
using NUnit.Framework;
using Test.TestUtilities;
using WebApplication.Data;
[TestFixture]
public class TestingDatabaseCreation
{
[Test]
public void TestCreation()
{
ApplicationDbContext context = TestDatabaseContextFactory.CreateDbContext();
}
}
}
Even though this test doesn’t assert anything, it will still pass, and with the added bonus that if we look in the output of the test run, we will see all the queries that have been run against the database.
Conclusion
This might not seem much, but it has become a standard to use it in my projects because even though the idea of unit tests is nice, there are times when our tests need to be small and fast but still do actual application logic, which most of the times especially when using SQL, the functionality doesn’t only live inside the application.
Keep in mind that this approach is using SQLite, so if you’re using some other database or a NoSQL database, look into their in memory variants if they have them. That being said, SQLite and SQL Server are different as well, but 9 out 10 functionalities that we will be using Entity Framework for is present in both.
I hope you enjoyed this post, and there are a few others related to Entity Framework Core on the horizon.
Cheers!
CodeProject