Nick Bauer
Nick Bauer

Reputation: 1072

Testing Entity Framework Core Migrations

How do you use unit/integration testing to ensure that a code-first migration works correctly on a populated previous-version database, including any additional code to map data from one column or table to another?

I found some previous answers that used classes in the System.Data.Entity namespace, but it appears these have become obsolete with Entity Framework Core and manual control of migrations is not possible?

I found a solution for myself which I will post, but I welcome other, better solutions.

Upvotes: 5

Views: 3749

Answers (1)

Nick Bauer
Nick Bauer

Reputation: 1072

The database is defined by a Context class, and ContextModelSnapshot class, a series of migration files, and the C# objects that the data tables store.

If you haven't created the migration yet, copy all of these files to your test project and rename the classes all with a suffix, e.g. "MyDataEntity" => "MyDataEntityVersion1". Edit the bundled .Design.cs files accordingly. Afterwards, create the new migration on the original.

If you have created the new migration but can't step back, you can manually edit the ContextModelSnapshot file to revert the changes.

The key to this working is that both point to the same database file. One expects the original state, and the other expects the upgraded state.

In your test case, you can then do:

[TestInitialize]
public void TestInit()
{
    using (var db = new MyDataContext())
        db.Database.EnsureDeleted(); // reset database before each test
}

[TestMethod]
public void Migrate_Version1_To_Version2_On_Populated_Database()
{
    using (var db = new MyDataContextVersion1())
        db.Database.Migrate(); // create database and apply migrations up through Version 1

    // populate the Version 1 database

    App.InitializeDatabase(); // whatever method you would normally call to read/update the database

    // assert statements to test that the Version 2 database looks like you expect.
}

where InitializeDatabase() looks something like:

public void InitializeDatabase()
{
    using (var db = new MyDataContext())
    {
        db.Database.Migrate();

        // detect if upgrade needed and set new columns

        db.SaveChanges(); 
    }
}

Note that this solution is in part motivated by using SQLite, which does not support dropping columns in a migration. It discouraged me from trying to do anything more fancy inside the migrations.

Upvotes: 1

Related Questions