Unit Testing with Entity Framework
Introduction
As part of the CQRS in Azure MSDN blog series, a unit test project was created to verify some of the functionality implemented using Entity Framework (EF). A challenge that often arises with unit tests is the challenge of stubbing or mocking databases. This article provides an example of using EF database migrations to provide a clean and seeded database for unit tests to run against.
The source can be found on MSDN Samples: here.
Unit Testing with Entity Framework
This example makes a couple of assumptions. The first is the unit test will be run on a machine that has a SQL Server instance available with a database to be used for running the unit tests. In the project source, this is controlled by a connection string in the app.config file of the unit test. The second is the database is maintained by code first migrations. This allows the database to be rebuilt before the unit tests are run.
Initial Migration
The initial migration consists of a DbMigration that creates a couple of tables. If unfamiliar with EF DbMigration, a sample is shown below (Note: This was generated from the defined classes):
public partial class initial : DbMigration
{
public override void Up()
{
CreateTable(
"ledger.Ingredients",
c => new
{
IngredientId = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.IngredientId);
CreateTable(
"ledger.Inventories",
c => new
{
InventoryId = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.InventoryId);
CreateTable(
"ledger.InventoryEntries",
c => new
{
InventoryEntryId = c.Int(nullable: false, identity: true),
InventoryId = c.Int(nullable: false),
IngredientId = c.Int(nullable: false),
Quantity = c.Int(nullable: false),
})
.PrimaryKey(t => t.InventoryEntryId)
.ForeignKey("ledger.Ingredients", t => t.IngredientId, cascadeDelete: true)
.ForeignKey("ledger.Inventories", t => t.InventoryId, cascadeDelete: true)
.Index(t => t.InventoryId)
.Index(t => t.IngredientId);
}
}
For more information on please see Entity Framework Code First Migrations.
Unit Tests
In the unit test project, a new database initializer is created by extending the DropCreateDatabaseAlways initializer. This will run the drop the schema in the database, run the defined migrations, and seed the database as illustrated below:
internal class TestPieShopDBInitializer : DropCreateDatabaseAlways<PieShopContext>
{
protected override void Seed(MSDN.AzureCQRS.Data.PieShopContext context)
{
context.Ingredients.AddOrUpdate(i => i.Name, new Ingredient { Name = "Flour" },
new Ingredient { Name = "Sugar" },
new Ingredient { Name = "Milk" },
new Ingredient { Name = "Water" },
new Ingredient { Name = "Salt" },
new Ingredient { Name = "Baking Powder" },
new Ingredient { Name = "Strawberry" },
new Ingredient { Name = "Lemon" },
new Ingredient { Name = "Pumpkin" },
new Ingredient { Name = "Blueberry" });
context.Inventory.AddOrUpdate(i => i.Name, new Inventory { Name = "Warehouse" },
new Inventory { Name = "Storeroom" });
}
}
As part of a unit test's startup, the db initializer is run:
[TestInitialize]
public void Reset()
{
Database.SetInitializer(new Resources.TestPieShopDBInitializer());
}
Summary
Unit tests are challenging to write and often requires stubbing or mocking of the back-end database. As an alternative approach, this article illustrates how the db could be initialized before unit tests are run.