Skip to content
  • English Deutsch

benjamin-abt.com

Performance is a feature | Cloud - AI - Azure - .NET - Sustainability

  • Home
  • Blog
  • Portfolio
    • Overview
    • Workshops & Training
    • Publications
  • Contact
  • Home
  • Blog

Easy InMemory Unit Tests with EFCore and Sqlite

Easy InMemory Unit Tests with EFCore and Sqlite
July 3, 2023 5 min read BEN ABT
.NET Csharp EF Core

This article was written in 2023. Versions, tools and recommendations may have changed since then. Newer posts are collected under .NET.

Unit testing is a type of software testing that is performed on the smallest unit of a software application, called a “unit”. A unit can be a function, method or module that is tested in isolation from other parts of the code.

The purpose of unit testing is to ensure that a single unit of software functions correctly and produces the expected results. To do this, test cases are developed that cover various inputs and situations and check the expected outputs. Unit tests are usually created and executed automatically to make the development process more efficient and reliable.

However, there are different opinions whether database functionalities should be solved via unit tests: because database providers have certain peculiarities that can only be tested against a real database.
In principle, I agree - but there are simply certain scenarios - like Linq queries - that can be covered super easily and stably via unit tests. Of course, however, these do not replace integration tests against real databases, which, however, have to be implemented with higher effort, costs and not always corresponding benefits.

Sqlite InMemory

To implement certain scenarios with the help of unit tests in .NET, I like to use Sqlite with its InMemory features, which is very easy and stable to use. This in itself is also the recommended variant, although nothing is said about the InMemory functionality of Sqlite itself. It is related to the fact that the InMemory database driver of EFCore is no longer developed, has immense vulnerabilities and incompatibilities and should simply not be used.

The .NET implementation of Sqlite (NuGet Package: Microsoft.EntityFrameworkCore.Sqlite ) also supports the InMemory behavior; it just has a certain peculiarity: InMemory is not supported by a name as known from other databases, but by a connection instance. If the connection is closed, the InMemory database is discarded.

C#
1// create test im-memory connection
2SqliteConnection sqliteConnection = new("DataSource=:memory:");
3
4// ..
5DbContextOptions<T> options = new DbContextOptionsBuilder<T>()
6                   .UseSqlite(sqliteConnection) // re-use connection
7                   .EnableSensitiveDataLogging(true)
8                   .Options;

Therefore, the test case must share the connection across multiple DbContext instances, which I implemented accordingly via a test helper class.

Test Helpers

To simplify the tests and their implementation I have written a small helper:

C#
 1/// <summary>
 2/// Static class to handle methods related to Sqlite database testing
 3/// </summary>
 4public static class TestSqliteDatabase
 5{
 6    /// <summary>
 7    /// Method to create a Sqlite connection for testing purposes
 8    /// </summary>
 9    /// <returns>SqliteConnection object for testing</returns>
10    public static SqliteConnection CreateSqliteTestConnection()
11    {
12        SqliteConnection connection = new("DataSource=:memory:");
13        connection.Open();
14        return connection;
15    }
16
17    /// <summary>
18    /// Method to create options for the provided SqlServerBaseDbContext
19    /// </summary>
20    /// <typeparam name="T">Type of SqlServerBaseDbContext</typeparam>
21    /// <param name="sqliteConnection">SqliteConnection to provide options for</param>
22    /// <returns>DbContextOptions object with options for the provided SqlServerBaseDbContext</returns>
23    public static DbContextOptions<T> CreateOptions<T>(SqliteConnection sqliteConnection) where T : SqlServerBaseDbContext
24        => new DbContextOptionsBuilder<T>()
25                   .UseSqlite(sqliteConnection)
26                   .EnableSensitiveDataLogging(true)
27                   .Options;
28
29    /// <summary>
30    /// Method to create a DbContext for the provided SqlServerBaseDbContext and connection
31    /// </summary>
32    /// <typeparam name="T">Type of SqlServerBaseDbContext</typeparam>
33    /// <param name="sqliteConnection">SqliteConnection to provide context for</param>
34    /// <returns>New instance of the provided SqlServerBaseDbContext connected to the provided SqliteConnection</returns>
35    public static T CreateContext<T>(SqliteConnection sqliteConnection) where T : SqlServerBaseDbContext
36    {
37        DbContextOptions<T> dbContextOptions = CreateOptions<T>(sqliteConnection);
38
39        T context = (T)Activator.CreateInstance(typeof(T), dbContextOptions)!;
40        context.Database.EnsureCreated();
41
42        return context;
43    }
44}

Test Case

A test case always has the same structure with regard to the test of the database functionalities:

  • Establishment of the connection, which is shared
  • First context instance for seeding the database
  • Second context to test the actual functionality
C#
 1[Fact]
 2public async Task My_Nice_Repository_Test_Case()
 3{
 4    // test database context
 5    using SqliteConnection testDbConnection = TestSqliteDatabase.CreateSqliteTestConnection();
 6
 7    // arrange
 8    // ...
 9
10    // create test database instance for seed
11    using (TenantsDatabaseSqlServerContext dbContext = TestSqliteDatabase.CreateContext<MyDatabaseMssqlServerContext>(testDbConnection))
12    {
13        // use this to seed your database
14
15        await dbContext.SaveChangesAsync(ct);
16    }
17
18    // create test database instance for query
19    using (TenantsDatabaseSqlServerContext dbContext = TestSqliteDatabase.CreateContext<MyDatabaseMssqlServerContext>(testDbConnection))
20    {
21        // act
22        // ...
23    }
24}

It is not necessarily the case that there is no third or fourth context; it is just essential to ensure that the Act part is given a new, fresh context and does not use the seed context, so that the test cannot be falsified.

Conclusion

Unit tests offer several benefits. They help developers detect and fix bugs early by isolating potential problems and preventing bugs from spreading to other parts of the application. Writing tests also more clearly defines requirements and unit behaviors, leading to better code quality and maintainability. Unit tests also facilitate refactoring by providing a safety net to ensure that changes do not have unwanted side effects.

Overall, unit tests are an important practice in software development to improve the quality and stability of an application. They help reduce bugs, increase developer productivity and improve customer satisfaction.

My variant to implement EF Core unit tests is very simple, works very stable and adds value to all my projects.

Related articles

Advanced Usage of MSSQL Indexed Views in EF Core

Jan 13, 2025 - 5 min read

Advanced Usage of MSSQL Indexed Views in EF Core

In the world of Microsoft SQL Server , views are a powerful tool for simplifying complex data queries. Simple views offer no real …

Increase Command Timeout for EF Core Migration Bundles

Jan 3, 2025 - 2 min read

Increase Command Timeout for EF Core Migration Bundles

EF Core Migration Bundles are standalone executable files that contain one or more Entity Framework Core migrations and can be applied …

New Data Annotation attributes with .NET 8

Nov 19, 2023 - 2 min read

New Data Annotation attributes with .NET 8

With .NET 8, the System.ComponentModel.DataAnnotations Namespace has been revised and some new attributes have been added that have been …


BEN ABT

BEN ABT

Ben is Chief Engineering Officer and Principal Software Engineer at Medialesson.de, with a strong focus on .NET and Microsoft Azure. In his professional role, he designs and builds highly scalable platforms for hybrid and cloud-based scenarios. He also advises companies and C-levels on migrating to the sovereign cloud.

He runs myCSharp.de, the largest and most active German-speaking C# community forum, actively contributes to both his own and external open-source projects and regularly shares his knowledge through his blog, at community events, conferences and as a writer for technical magazines.

Let's Work Together

Looking for an experienced Platform Architect or Engineer for your next project? Whether it's cloud migration, platform modernization or building new solutions from scratch - I'm here to help you succeed.

New Platforms

Modernization

Training & Consulting

Contact Me
X Facebook LinkedIn WhatsApp
Back Next Blog Post

Open for work!

Contact Me
BEN ABT BEN ABT Software Engineer · Microsoft MVP Passionate about .NET, Azure, performance optimization and sustainable software engineering.

Medialesson GmbH Logo

Microsoft MVP Logo

Recent posts

View all
Stop Using nginx as Your Default Static File Server in Docker

Stop Using nginx as Your Default Static File Server in …

Oct 24, 2026
Containerizing .NET in 2026 Without a Dockerfile

Containerizing .NET in 2026 Without a Dockerfile

Oct 20, 2026
Problem Details in ASP.NET Core and .NET 11

Problem Details in ASP.NET Core and .NET 11

Oct 5, 2026
Resilience in .NET with Microsoft.Extensions.Resilience

Resilience in .NET with Microsoft.Extensions.Resilience

Sep 21, 2026
What Matters in ASP.NET Core 11

What Matters in ASP.NET Core 11

Sep 14, 2026

Tags

.NET (192) Csharp (96) ASP.NET Core (48) Azure (41) DevOps (17) Docker (14) Microsoft (14) EF Core (11) Microsoft MVP (11) AI (10) GitHub (10) GitHub Copilot (10) ASP.NET (9) Security (9) Synology (9) Architecture (8) Raspberry (8) Azure Functions (7) Cloudflare (7) Bicep (6)
benjamin-abt.com

About BEN

Benjamin Abt is a Software Engineer, Platform Architect and Microsoft MVP specializing in .NET, Azure, cloud architecture, performance optimization and sustainable software development.

Connect

  • Follow me on GitHub
  • Follow me on LinkedIn
  • Follow me on Mastodon
  • Microsoft MVP profile
  • Follow SchwabenCode on GitHub
  • Follow me on X

Quick Links

  • Portfolio
  • Blog
  • Workshops & Training
  • Publications
  • Get in Touch
  • Sitemap
Open for Work

© Copyright Benjamin Abt & SchwabenCode | 2011 - 2026

Content licensed under CC BY 4.0 unless otherwise noted.

  • Impressum
  • Privacy
  • Contact