Test DB reset with Respawn

When doing testing against DB it is important to reset it to initial state. I am using Entity Framework for SQL DB access and it provides mechanism to recreate DB each time, but it is slow and sometimes fails because of open DB connections. Much easier is to delete everything from tables and Respawn is great too which helps to do it.

Respawn is created by Jimmy Bogard. You can find documentation on tool's Github page.

For my purpose, I needed cleaning all my tables in test DB, but sometimes I also required to recreate the whole DB when schema had changed. I am also writing my DB tests so that those do not depend on other tests and that those do not conflict with data already in tables. Because of that I can reset DB only once when running tests.

As I am using xUnit.net, I can use Collection Fixture which will trigger DB reset for my DB tests. It will reset DB once per test run.

First define fixture which resets DB. It is a simple C# class with default constructor where reset should happen. Create Checkpoint as a static field and optionally initialize with tables you want to skip, or schemas to ignore and other settings. Then in constructor call Reset method with the connection string.

public class DbFixture
{
    private static readonly Checkpoint Checkpoint = new Checkpoint();

    public DbFixture()
    {
        var connectionString = ConfigurationManager
                                    .ConnectionStrings["AppConnectionString"]
                                    .ConnectionString;
        Checkpoint.Reset(connectionString);
    }
}

Now define fixture collection.

[CollectionDefinition("DbCollection")]
public class DbFixtureCollection : ICollectionFixture<DbFixture> { }

And use this collection for DB tests by decorating test class with Collection attribute. Collection attribute's name should match CollectionDefinition attribute's name on fixture collection class.

[Collection("DbCollection")]
public class EntityRepositoryTests
{
    [Fact]
    public void getById_returns_existing_entity()
    {
        ...
    }
}

Now DB will be reset once for all tests in same fixture collection before each test run.

Next task is to re-create database when needed. To achieve that first I will create a special attribute for the test which will run only in debug mode. Jimmy Bogard wrote an article how to create such RunnableInDebugOnlyAttribute.

public class RunnableInDebugOnlyAttribute : FactAttribute
{
    public RunnableInDebugOnlyAttribute()
    {
        if (!Debugger.IsAttached)
        {
            Skip = "Only running in interactive mode.";
        }
    }
}

Then create a test which recreates DB. Use Entity Framework's DropCreateDatabaseAlways initializer in the test.

public class DatabaseSeedingInitializer
    : DropCreateDatabaseAlways<WebshopDbContext> { }

public class SchemaCreationTest
{
    [RunnableInDebugOnly]
    public void Wipe_Database()
    {
        Database.SetInitializer(new DatabaseSeedingInitializer());
        using (var context = new AppDbContext())
        {
            context.Database.Initialize(true);
        }
    }
}

Testing against database might be hard, but if you have good tools, then it is not much harder than unit testing.