다음을 통해 공유


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.