3

Entity Framework Core In Memory Testing

 2 years ago
source link: https://www.scottbrady91.com/entity-framework/entity-framework-core-in-memory-testing
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Entity Framework Core In Memory Testing

When writing tests you don’t always want to use a physical database, instead opting for an in-memory solution. Whatever your reasons for doing this, with the release of Entity Framework Core we now have a couple of different options recommended by the EF team for when we are testing using in-memory databases.

These two choices for in-memory database providers depend on whether or not you’re using the Microsoft.EntityFrameworkCore.Relational package and if you need the full behaviour of a relational database during testing.

If this doesn’t apply to you, you can use the Entity Framework Core In-Memory Database Provider (Microsoft.EntityFrameworkCore.InMemory). If you do need this behavior, you can use the SQLite Database Provider (Microsoft.EntityFrameworkCore.Sqlite) using the SQLite in-memory mode.

For the below two examples we are going to use the xUnit test framework. To find out how to set up an xunit test see the xUnit .NET Core Getting Started section of the xUnit documentation. Otherwise the test project containing the below code is available on GitHub.

Testing Entity Framework Core using In-Memory Database Provider

The InMemory provider is sold as something that "approximates connecting to the real database, without the overhead of actual database operations", with the caveat that it is not suitable for mimicking a relational database.

To use the In-Memory database provider first we need to add the following nuget package by either adding it to our project.json or via the nuget package manager:

Microsoft.EntityFrameworkCore.InMemory

In order to create an instance of a DbContext to use for our tests, we must first create an instance of DbContextOptions. By default a DbContext has a constructor parameter of either DbContextOptions or DbContextOptions<TContext>, where we prefer the generic version as it allows multiple DbContext types to be used at once. To create an instance of DbContextOptions outside of the ASP.NET Core dependency injection pipeline, we can use the DbContextOptionsBuilder class.

DbContextOptions<TestDbContext> options;
var builder = new DbContextOptionsBuilder<TestDbContext>();
builder.UseInMemoryDatabase();
options = builder.Options;

Here we are using the DbContextOptionsBuilder to assign our database provider via the use of UseInMemoryDatabase and then use its Options property to get our configured instance of DbContextOptions. We can then pass this DbContextOptions into the constructor of our DbContext for testing.

[Fact]
public void CanAddEntity() {
    var testEntity = new TestEntity {Id = 1, Name = "Test Entity"};

    using (var context = new TestDbContext(options)) {
        context.TestEntities.Add(testEntity);
        context.SaveChanges();
    }                             

    TestEntity foundEntity;
    using (var context = new TestDbContext(options)) {
        foundEntity = context.TestEntities.FirstOrDefault(x => x.Id == testEntity.Id);
    }                             

    Assert.NotNull(foundEntity);
    Assert.Equal(testEntity.Name, foundEntity.Name);
}

And that’s all that is required to configure the Entity Framework Core In-Memory database provider!

To create a named instance of an In-Memory database, you can pass a name in as a string to the UseInMemoryDatabase extension method (e.g. UseInMemoryDatabse("test1")). This can be used to prevent data collisions.

Testing Entity Framework Core Relational Databases using SQLite In-Memory Mode

The SQLite provider itself is another relational database provider but we can take advantage of SQLite in-memory mode. The nice thing about this provider is that we get the full behavior of a relational database, with the benefits of the running in-memory.

Configuring DbContextOptions for SQLite In-Memory is a little more involved than the In-Memory database provider:

var connectionStringBuilder =
  new SqliteConnectionStringBuilder { DataSource = ":memory:" };
var connectionString = connectionStringBuilder.ToString();
var connection = new SqliteConnection(connectionString);

DbContextOptions<TestDbContext> options;
var builder = new DbContextOptionsBuilder<TestDbContext>();
builder.UseSqlite(connection);
options = builder.Options;

using (var context = new TestDbContext(options)) {
    context.Database.OpenConnection();
    context.Database.EnsureCreated();
}

Here we configuring a new SqliteConnection via the SqliteConnectionStringBuilder class. By using using this we avoid an exception when trying to use ":memory:" as our connection string (otherwise we get: ArgumentException "Format of the initialization string does not conform to specification starting at index 0").

We can then pass this SqliteConnection into our UseSqlite extension method.

Another step required for the SQLite provider is to call both the OpenConnection and EnsureCreated methods on the context’s DatabaseFacade. Otherwise we are met with a DbUpdateException: "SQLite Error 1: 'no such table: TestEntites'".

Once we have created our options this way, we can then pass those options to our DbContext during our test like before.

By default each SQLite connection using the ":memory:" connection string will use a different in-memory database (the opposite of the entity framework core in-memory database provider). To override this behavior check out the 'In-memory Databases And Shared Cache' section of the SQLite in-memory databases documentation.

Do not use only in-memory testing for your Entity Framework Core tests. As you can see from the providers in this article: every provider is different, so make sure you write integration tests that target your provider of choice.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK