Help, my tests using EF Core see an incorrect model

Jun 20, 2023  

I’m still a relatively new and inexperienced user of EF Core (v7). I am working with multiple test projects, which all use a common DbContext called DataFridgeDbContext. The DataFridge library I am developing provides dynamic registration and discovery of entities, which are produced by some code generator, which is turning all IDbXxx interfaces into DbXxxEntity classes:

public interface IDbEmployee
{
    string FirstName { get; }
    string LastName { get; }
    DateOnly BirthDate { get; }
}

Testing the library

The model attached to the DbContext can therefore be completely different from one project to another; this is even the case between multiple tests in a given test project.

Wrong model: the entity type was not found

When running my tests manually, one after the other, I never see any issues. But as soon as I run two tests using different EF Core models, I get weird errors:

System.InvalidOperationException: The entity type 'DbEmployeeEntity' was not found. Ensure that the entity type has been added to the model.

The stack trace points to StateManager.GetOrCreateEntry() which relies on its constructor for its various related services, in particular the IModel which happens to be the same instance in the first and in the second test methods!

Caching is (usually) your friend

Digging deeper into StateManagerDependencies and into EF Core’s source code on GitHub, I finally realized that there was some weird static caching going on under the hood in order to speed up service resolution.

For the curious, have a look at ServiceProviderCache.Instance on GitHub.

This caching is an essential feature which allows EF Core to perform reasonably well. Without it, EF Core would have to analyze the schemas at runtime, over and over again, every time a new instance of a DbContext gets created.

For my tests, however, this is really annoying since I cannot afford to create different DbContext classes for my various models (indeed, this would defeat the very idea of dynamic discovery provided by the DataFridge).

Disable Service Provider Caching for your tests

Microsoft thanfully provides a solution to disable the caching behavior. You have to call EnableServiceProviderCaching(false) on the DbContextOptionsBuilder when configuring the DbContextFactory used by the tests.

In my case, the initialization code looks like this:

services.AddPooledDbContextFactory<DataFridgeDbContext> (
    (sp, optionsBuilder) =>
    {
        // ...
        optionsBuilder.UseSqlite (connectionString, /* ... */);
        optionsBuilder.EnableSensitiveDataLogging (true);
        optionsBuilder.EnableServiceProviderCaching (false);
    });

See this article on learn.microsoft.com for the documentation of this feature.