Code First Entity Framework Unit Test Examples
TweetFollowing 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:
- Microsoft ADO.NET Entity Framework Feature Community Technology Preview 4
- Microsoft SQL Server Compact 4.0 Community Technology Preview for Windows Desktop
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.
Pingback: The Morning Brew - Chris Alcock » The Morning Brew #655