Code First Entity Framework Unit Test Examples

Following the release of the Entity Framework 4 CTP 4 and Scott Gu’s excellent blog post about Code-First Development with Entity Framework 4, we’ll be having a look at what your Code-First Entity Framework unit tests might look like.

The code used in this post is available here.

Remember in order to run the code or to create unit tests shown in this post you need to download and install:

Getting started

The entities we will be using are the same Dinner and RSVP entities Scott used in his post

public class Dinner
{
    public int DinnerID { get; set; }
    public string Title { get; set; }
    public DateTime EventDate { get; set; }
    public string Address { get; set; }
    public string Country { get; set; }
    public string HostedBy { get; set; }

    public virtual ICollection<RSVP> RSVPs { get; set; }
}

public class RSVP
{
    public int RsvpID { get; set; }
    public int DinnerID { get; set; }
    public string AtendeeEmail { get; set; }

    public virtual Dinner Dinner { get; set; }
}

as well as the NerdDinners class which inherits from DbContext

public class NerdDinners : DbContext
{
    public DbSet<Dinner> Dinners { get; set; }
    public DbSet<RSVP> RSVP { get; set; }        
}

Creating Entity Framework Code-First Unit Tests

So let’s start off by writing a test to check a Dinner can be saved in the database.

[Test]
public void Should_be_able_to_save_new_dinner()
{
    // Arrange
    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    NerdDinners nerdDinners = new NerdDinners();

    Dinner dinner = new Dinner
                        {
                            Title = "Dinner with the Queen",
                            Address = "Buckingham Palace",
                            EventDate = DateTime.Now,
                            HostedBy = "Liz and Phil",
                            Country = "England"
                        };

    nerdDinners.Dinners.Add(dinner);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    Dinner savedDinner = (from d in nerdDinners.Dinners
                            where d.DinnerID == dinner.DinnerID
                            select d).Single();
                                                       
    savedDinner.Title.ShouldEqual(dinner.Title);
    savedDinner.Address.ShouldEqual(dinner.Address);
    savedDinner.EventDate.ShouldEqual(dinner.EventDate);
    savedDinner.HostedBy.ShouldEqual(dinner.HostedBy);
    savedDinner.Country.ShouldEqual(dinner.Country);            
}

There are a couple of things to note here.

In the LINQ query to get the saved Dinner from the database we can use the ID of the Dinner we created because when you call the SaveChanges() method the Entity Framework will set the identity value of the object(s) being persisted.

The other thing we could have done is use a ‘domain signature’ to check for equality, but that’s for a future blog post.

Testing entities with foreign keys

The code below shows a test for saving an RSVP.

[Test]
public void Should_be_able_to_save_new_rsvp()
{
    // Arrange
    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");            
    NerdDinners nerdDinners = new NerdDinners();

    RSVP rsvp = new RSVP();
    rsvp.AtendeeEmail = "someone@somedomain.com";
    Dinner dinner = new Dinner
                        {
                            Title = "Dinner with the Queen",
                            Address = "Buckingham Palace",
                            EventDate = DateTime.Now,
                            HostedBy = "Liz and Phil",
                            Country = "England"
                        };            
    rsvp.Dinner = dinner;

    nerdDinners.RSVP.Add(rsvp);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    RSVP savedRSVP = (from s in nerdDinners.RSVP
                        where s.RsvpID == rsvp.RsvpID
                        select s).Single();
            
    savedRSVP.AtendeeEmail.ShouldEqual(rsvp.AtendeeEmail);
}

One thing you might have noticed here is that we had to create a Dinner as well as an RSVP. This is because of the foreign key constraint for the DinnerID.

So at this point you could be asking why we can’t use the Dinner we created in the first test? The trouble, danger and bad practice of doing that is falling into the trap of creating a dependency of your tests running in some sort of order or sequence.

AlwaysRecreateDatabase

In his post Scott created a NerdDinnersInitializer class which inherited from RecreateDatabaseIfModelChanges. But this is not good enough for a unit test because we need to ensure each test starts off in a known state.

This doesn’t mean we have to create a Dinner each time we want to save an RSVP because we can create an NerdDinnersInitializer which is already populated with a dinner by overriding the Seed method.

public class NerdDinnersInitializer : AlwaysRecreateDatabase<NerdDinners>
{
    protected override void Seed(NerdDinners context)
    {
        var dinners = new List<Dinner> { new Dinner()
                                                {
                                                    Title = "Dinner with the Queen",
                                                    Address = "Buckingham Palace",
                                                    EventDate = DateTime.Now,
                                                    HostedBy = "Liz and Phil",
                                                    Country = "England"
                                                }
        };
        dinners.ForEach(d => context.Dinners.Add(d));
    }
}

And use it in a test to check we can create an RSVP

[Test]
public void Should_be_able_to_save_new_rsvp_using_existing_dinner()
{
    // Arrange
    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    Database.SetInitializer<NerdDinners>(new NerdDinnersInitializer());
    NerdDinners nerdDinners = new NerdDinners();

    RSVP rsvp = new RSVP();
    rsvp.AtendeeEmail = "someone@somedomain.com";           
    rsvp.DinnerID = nerdDinners.Dinners.First().DinnerID;
            
    nerdDinners.RSVP.Add(rsvp);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    RSVP savedRSVP = (from s in nerdDinners.RSVP
                        where s.RsvpID == rsvp.RsvpID
                        select s).Single();
            
    savedRSVP.AtendeeEmail.ShouldEqual(rsvp.AtendeeEmail);
}

The disadvantage of always creating a database is the amount of time it takes to actually create the database

So the more times you call SetInitializer in which you’re always recreating a database, the longer it will take for your tests to run.

My recommendation is to create dummy/stub dinners upfront and call SetInitializer before you run the tests. In NUnit this is done in the TestFixtureSetUp as shown below.

[TestFixtureSetUp]
public void TestFixtureSetup()
{
    Database.SetInitializer<NerdDinners>(new NerdDinnersInitializer());
}

Tests to check updates

So now you can save a Dinner, the next test you might write is to check you can update it.

[Test]
public void Should_be_able_to_update_existing_dinner()
{
    // Arrange    
    NerdDinners nerdDinners = new NerdDinners();

    Dinner dinner = nerdDinners.Dinners.First();
    dinner.HostedBy = "Charlie and Camilla";

    // Act
    nerdDinners.SaveChanges();

    // Assert
    Dinner savedDinner = (from d in nerdDinners.Dinners
                            where d.DinnerID == dinner.DinnerID
                            select d).Single();

    savedDinner.HostedBy.ShouldEqual(dinner.HostedBy);
}

Testing your models

The examples in this post follow the Entity Framework convention you get out of the box.

As we have already established the property DinnerID is a foreign key in the RSVP entity.

But if you forgot to add it, the Dinner property would always be null.

The test below verifies we are able to view information about a dinner when we retrieve an RSVP from the database.

[Test]
public void Should_be_able_to_view_dinner_details()
{
    // Arrange            
    NerdDinners nerdDinners = new NerdDinners();
    var dinner = nerdDinners.Dinners.First();

    RSVP rsvp = new RSVP();
    rsvp.AtendeeEmail = "someone@somedomain.com";
    rsvp.DinnerID = dinner.DinnerID;

    nerdDinners.RSVP.Add(rsvp);

    // Act
    nerdDinners.SaveChanges();

    // Assert
    RSVP savedRSVP = (from s in nerdDinners.RSVP
                        where s.RsvpID == rsvp.RsvpID
                        select s).Single();

    savedRSVP.Dinner.Title.ShouldEqual(dinner.Title);
}

Jag Reehal’s Final Thought on ‘Examples of Code First Entity Framework Unit Tests’

In this post I wanted to show a few examples of how you might create unit tests for your Entity Framework projects.

The ADO.NET team have really done a great job enabling developers to be able to do code-first development and allow them to move a step closer to doing test driven development using the Entity Framework.

Comments

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #655

  • http://nileshgule.blogspot.com Nilesh Gule

    This is really a nice post. I was looking at FluentNHibernate and its Persistance based testing capabilities. I hope some day EF team will come up with something similar.

  • Jedidja

    How are you able to run these tests more than once? I tried something similar (and also from your zip file) and get this error as soon as you attempt to run them the second time.

    System.Data.SqlServerCe.SqlCeException : File already exists. Try using a different database name.

  • http://www.arrangeactassert.com Jag Reehal

    Hi Jedidja,

    I know that didn’t happen when this blog post was written, but I’m also getting the same error as you. It’s odd the error only happens for the first test that is run.

    I suspect an update has caused the error because hasn’t been updated with any of the latest versions of software/components the unit tests run without any problems.

    I’ll come back to you when I find a solution.

    Cheers,

    Jag

  • http://www.arrangeactassert.com Jag Reehal

    Hi Jedidja,

    Which CTP version of Microsoft Sql Server Compact 4.0 are you using?

    When I’m using CTP 1 all the unit tests run successfully.

    When I’m using CTP 2 the first unit test that is run always fails.

    Cheers,

    Jag

  • http://rocketba.se Mark

    This is a SQL CE CTP 2 issue and has started happening to me on a random basis not just unit testing

  • http://francisconoriega.com Francisco Noriega

    I also have the same problem, how can I go back to ctp 1?

  • http://www.arrangeactassert.com Jag Reehal

    Hi Francisco,

    You can download CTP 1 here Microsoft SQL Server Compact 4.0 Community Technology Preview for Windows Desktop

    Cheers,

    Jag

  • http://francisconoriega.com Francisco Noriega

    Great! I just had to uninstall the CTP 2.. but after that it worked

  • Paul

    Thanks for the post, it’s appreciated. I note that you mention saving “domain signatures” for a future post, but haven’t seen that yet. I was hoping that’s still forthcoming? I am familiar w/ the domain signature concept from S#harp architecture and elsewhere but am curious as to how to implement it in EF CodeFirst.