Integration Testing with Entity Framework

I’ve been writing a lot more integration tests for my recent projects in which I’ve made use of Entity Framework. I’m purely using code first as I never really got along with the whole draggy droppy designer affair. I came to realise recently that I was writing an awful lot of code to mock out my data layer (using Moq). But all I was really doing was making sure that my Linq queries pulled back the correct data. Even after having gone to all the effort I was still getting problems with my code when it got to see a database for the first time. Usually to do with me doing things which cannot be converted in to T-SQL. So I’ve decided to ditch unit testing and mocking for any data layer stuff and go totally over the integration testing. Making the move to entity framework code first has made that very simple. First off I create a couple of “self-creating” properties for my Context and Repository.

private DomainContext _context;
protected DomainContext Context
{
    get { return _context ?? (_context = new DomainContext(ConfigurationManager.ConnectionStrings["ByBox"].ConnectionString)); }
    private set { _context = value; }
}

private ConsumerRepository _repository;
private ConsumerRepository Repository
{
    get { return _repository ?? (_repository = new ConsumerRepository(Context)); }
    set { _repository = value; }
}

Then I have some straight forward setup/teardown code. All this usually ends up in a base class of some kind which I re-use in all my different test source files.

[TestFixtureSetUp]
public virtual void TestFixtureSetUp()
{
    try
    {
        var seed = new DomainDataSeed();
        Database.SetInitializer(seed);
        Context.Database.Initialize(true);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
        throw;
    }
}

[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
    Repository.Dispose();
    Repository = null;
    Context.Dispose();
    Context = null;
}

Another useful thing to do is to be able to reset the database to a know state. You may have noticed these 3 lines above …

var seed = new DomainDataSeed();
Database.SetInitializer(seed);
Context.Database.Initialize(true);

What these do is use a data seed class to initialise the database. By way of example, here is a snippet from my seed class …

public class DomainDataSeed : DropCreateDatabaseAlways<DomainContext>
{
    protected override void Seed(DomainContext context)
    {
        AddWebServiceUsers(context);
        AddUserAccounts(context);

        context.SaveChanges();
    }

    private void AddWebServiceUsers(DomainContext context)
    {
        context.Database.ExecuteSqlCommand("CREATE TABLE [web_service_user] ( ... )");
        context.Database.ExecuteSqlCommand("CREATE TABLE [web_service_user_attribute] ( ... )");
        context.Database.ExecuteSqlCommand("INSERT INTO [web_service_user] ([username], [password]) values({0}, {1})", Username, Password);
    }

    private static void AddUserAccounts(DomainContext context)
    {
        context.UserAccounts.Add(
            new UserAccount
            {
                ...
            });
    }
}

If I wanted to I could put that code into the [SetUp] method rather than the [TestFixtureSetUp] method. Or, as I have done recently in a ResetDatabase() method, which I call from the [TestFixtureSetUp] and select tests as required. This particular seed class drops and re-creates the database every time it is called, thanks to this – DropCreateDatabaseAlways<DomainContext>. There are other options available, including only dropping and re-creating the database (and seeding it) when the model changes.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s