Testing with xUNIT and InMemory database, Entity Framework Core

I ran into an issue where some of my tests didn’t pass when I ran all my tests but passed if I ran them individually.
After some research, I found a solution that worked perfectly, so I thought I would share it with you guys, in case you run into the same problem.

I first created a ContextFactory that implements IDisposable. For this example, I’m using the context that I have in my Battle Arena project.

public class BattleArenaContextFactory
    {
        public static BattleArenaDbContext Create()
        {
            var options = new DbContextOptionsBuilder<BattleArenaDbContext>()
                .UseInMemoryDatabase(Guid.NewGuid().ToString())
                .Options;

            var context = new BattleArenaDbContext(options);

            context.Database.EnsureCreated();
            SeedCharacters(context);
            SeedItems(context);

            context.SaveChanges();

            return context;
        }

        public static void Destroy(BattleArenaDbContext context)
        {
            context.Database.EnsureDeleted();
            context.Dispose();
        }

So the class has a static method called Create, which sets the options for the DbContext to use InMemoryDatabase passing in a Guid as the name to make it unique.
I then have two methods that just seed some dummy data for testing, in this case, some items and characters.

The class also has implemented Destroy, which ensures the database is deleted and disposes of the context.

With the factory in place, I created a base class for my tests:

    public class TestBase : IDisposable
    {
        protected readonly BattleArenaDbContext Context;

        public TestBase()
        {
            Context = BattleArenaContextFactory.Create();
        }

        public void Dispose()
        {
            BattleArenaContextFactory.Destroy(Context);
        }
    }

TestBase also implements IDisposable. It has a field variable for the Context that gets created through the factory’s static method in the constructor.
And the Dispose method calls the Destroy method from the ContextFactory.

So with that in place, let’s write a test!

public class TavernCommandTests : TestBase
{
    [Fact(DisplayName = "Rest_HasEnoughGold_ShouldRegainMaxHealth")]
    public async Task Rest_HasEnoughGold_ShouldRegainMaxHealth()
    {
        // Arrange
        var character = Context.Characters.Find(1);
        var previousGold = character.GoldCoins;

        // Assert
        var sut = new RestCommandHandler(Context);
        var result = await sut.Handle(new RestCommand { CharacterId = character.Id }, CancellationToken.None);

        // Assert
        character.Stats.Health.ShouldBe(character.Stats.MaxHealth);
        character.GoldCoins.ShouldBe(previousGold - 20);
        result.Success.ShouldBe(true);
    }

}

My game has a Tavern that has a rest function that restores health, this costs 20 gold coins and the character should regain full health.

Arrange
I get the first character from the in-memory database, note that Context is from the base class.
I store the previous gold in a variable to make the test more readable.

Act
I’m using Mediator so I make an instance of my handler and passing in the mocked context, my application layer and all handlers are using an abstraction of the context (IDbContext) to make this possible.
I tell my handler to Handle a request of RestCommand and passing in the character’s id.

Assert
For my assertion, I’m using Shouldly (which is awesome by the way).
As we can see:
– The character’s health is now equal to its maxed health.
– The character’s gold is now equal to its previous golds minus 20.
– The command should return a result object with its Success property being true.

All this without having to create an instance of the context in each method that uses it, as well as not having any issues running all tests at once, since this pattern makes sure each method has a fresh instance of the Context and disposes of it after it’s used.