One thing that always keeps nagging at me with unit tests is the problem of simulating the database without actually hitting the database. Of course, you can hit the database during your unit tests to make sure everything works, but then they are called integration tests.

So how can you simulate a database as close as possible in your unit tests without hitting a database?

Also, what happens when you have deep objects that need testing? Your customer has an order, the order has details, and your details have a product. You need to create three nested objects inside of your customer object just to test whether a product is available or not. Imagine writing that fake.

Throw in Entity Framework to the mix and you have an interesting issue. While Entity Framework helps you with the development of your models, it can also be a problem mocking up the DbContext, DbSets, and repositories for all of your tables.

Today, I will show you a better way to come as close to a production database as possible...all through unit tests.

Throw It Into Reverse!

For our example today, we will be using the Northwind database for our "production data." It's a complete schema with all of the trimmings, a load of data, and a little bit older sample database (I know there is the updated AdventureWorks database, but I'm a little nostalgia). ;-)

Once that's imported (or created) in your SQL Server, we now focus on Entity Framework.

POCO LOCO!

As mentioned before in my ludicrous speed post, I like to speed up my EF development with the Entity Framework Reverse Engineer Code First POCO Generator (Phew! That's a mouthful).

After we install the plugin, the instructions can be found on that extension page on how to use it or I can refer you to the link above ("ludicrous speed") to understand how to use it. Either way, when you are done, you should have a long list of entities from your database.

Once that's done, we need to modify the T4 template for our needs. Here are the steps to modify the template:

Open the EF.Reverse.POCO.Core.ttinclude in your favorite editor.

Go to the "AddReverseNavigation" method (~lines 2530-2555 for version 2.1.4.3)

In the Relationship.ManyToOne and Relationship.ManyToMany enumerated types, change the type from "virtual ICollection" to "virtual Collection" We need a concrete class for what we're about to do.

Save the file.

Now that you have your entities created we need to create our data.

There is only one structure we can provide that will give us the hierarchical data we need for our entity framework objects: XML.

But how do we populate our objects using the XML? Serialization! Or actually...Deserialization.

This is why we needed the T4 template to generate concrete classes as opposed to interfaces. When you deserialize the XML into an object, it will traverse through your entire entity framework objects and error every time it encounters the interface.

Retrieving the Data

So now, how do we create XML hierachical data for our unit tests?

That's where we move over to SQL Server. SQL Server has this snazzy feature of spitting out XML from your select statements.

So let's make the data for our simple tables. We'll start with the Customers and Orders table.

In Query Analyzer, when I type in:

If you notice, I also have a root of ArrayOfCustomer. Since this is just data for a unit test, I need a container for this data and the default for the deserialization to work is 'ArrayOf<type>'.

When I execute that SQL, I get the following XML:

I kept it to a region of Washington ('WA') because there are a LOT of customers in this database.

Now we have our records. Perform the same process on the tables that you want for your unit tests.

Finally!...Unit Tests!

With our data in hand, we can start working on our unit tests.

Here is how we integrate our data into our unit tests:

In your unit test project, Add a Resources folder.

In that Resources folder, create a Resource file. I called mine NorthwindData.resx.

In that Resource file, I added an entry name called CustomerData and pasted the Customer XML into the Value column.

Repeat this for each table that you want to unit test.

I am using Moq for these unit tests.

There was also a DbSetExtensions extension method to convert an IEnumerable into a DbSet for us.

If you're wondering where the ToStream() extension method came from, it's from a previous post called on a previous post called 10 Extremely Useful .NET Extension Methods.

The INorthwindContext was created along with our entities in the T4 generator so that was a bonus for mocking up our DbContext.

Everything passes and we're in business.

That's all for today! Good night, folks! Be sure to tip your waitress!

But Wait...There's More!

Still here, huh?

Wanting a little more?

Ok. Let's revisit the first problem we explained in the beginning. How do we test objects from all levels throughout an object hierarchy all the way down to the lower depths of the nested tree.

Well, since our last example uses one table to generate a single XML file for customers, I'm pretty sure we can create a new XML source to include more data to make our unit test complete.

If I bring up the Northwind database and in SQL Server's Query Analyzer, I type:

I receive the following XML (shortened because of space):

etc., etc., etc.

We can see that based on our query, we have the one customer who has 2 orders, each order has 1 order detail a piece, and each one has a product.

Now we have our hierarchical data for testing. A couple of notes before we proceed:

As you can imagine, you can get a TON of XML returning from SQL Server. Try to minimize the amount of data returned to make your unit tests pass. I'll show you in a minute why you should keep it small.

The great part about this is that you can run your unit tests under any number of specific conditions. Modify the XML for your unit test and you're off and running.

The aliases make a difference when outputting your XML through SQL Server. Adjust the aliases to get your proper names relating to your entity framework classes.

Since Entity Framework uses relationships when creating the code first entities, make sure they are defined in your tables before you generate the entities. Otherwise, you won't be able to perform your serialization.

Our unit test will be exactly what you would expect. If we create a new entry in our Resource file called CustomerOrderData, we can run the following Unit Test with a pass.

Conclusion

With this technique, you can easily make changes to your unit test data and run experiments on the XML and your business rules. This is will make your Entity Framework Unit Tests more believable with "real" data.

How many of you have had an issue with production where it works on staging, but doesn't work on production...

...and the source code is the same in both environments. :-\

This is one example of being able to take data from a SQL Server (with the query above) from production and immediately place it on your staging server with your code and run it against staging to find out where your issue is and how you can resolve it.

In the long run, this makes your unit tests even more valuable to you.

I hope you enjoyed this technique. Have you implemented something like this before? Post your comments below.

Show more