Tips and Tricks

Implementing Effort into a C# MVC Website to allow Unit Testing

I recently wanted to have the ability to write Unit Tests for a personal project, I picked Effort.EF6 to help. This post goes through the setup for "Effort" and why you should choose it.

Author Avatar

Author: Tom McClean

Updated: 02 Oct 2016 19:09

Effort is an Entity Framework Unit Testing tool. I needed to use it recently on a personal project so that I could Unit Test new and existing functionality, I hadn't done this until now for the reasons I describe later in this post.

This post goes through the difficulties with introducing Unit Tests retrospectively and how Effort can solve some common problems for developers trying to effectively Unit Test their code. This Post shows you how we set it up so that you can do the same.

 

The technology stack this guide was written alongside was C# MVC with Entity Framework 6 and StructureMap for Dependency Injection. If you get stuck and want to see a working example - you can check my code on GitHub - https://github.com/tommcclean/PortalCMS

 

A big problem you face when you use Entity Framework and want to Unit Test your code, is that if you use the EF Context in your tests directly like you do in code - you may make unexpected changes to your database.

Even if you can find a way of ensuring your test data does not affect actual users of your site, it's still not a good idea to allow it access to your database, here are a few reasons why...

  • You aren't supposed to be testing external systems like your database.

  • Your Unit Tests will not run very quickly if each test involves saving changes to your database.

  • Your tests could be contaminated by existing data in the database or data created by other tests.

  • You may accidentally write a test that affects live data and causes problems for users (or the stability) of your site.

 

So what are your options?

So while its clear that your Unit Tests should not be interacting with your website, there are many options you might look at for being able to write Unit Tests in other ways. They might include implementing a Repository Pattern in your code base or refactoring your methods to extract out database interactions.

Neither of those options are a good idea, why?

  • Firstly the Repository pattern doesn't cover Entity Framework's internal logic.

    • It is true that you shouldn't be writing Unit Tests for standard functionality provided by your libraries, but if you do completely remove Entity Framework from the equation as repository patterns tend to do, your services do not reflect the behaviour they will use in production. For example - How do you know a change you make won't cause Entity Framework to complain about keys or null values when saving an Entity?

    • What about the functionality you take for granted that doesn't work without Entity Framework, like the automatic population of primary keys, which affects the relationship between your entities.

    • If you aren't already using a Repository pattern in your code, it would also be very time consuming to change it all to utilise the new pattern you choose.

    • It is quite easy to find other architectural arguments against using a Repository pattern with Entity Framework online, here is an example: http://rob.conery.io/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/

  • Refactoring your code to extract out database interactions is not great either.

    • If you already have a large code base it would be a huge effort and a big risk to refactor it to extract out all database interactions leaving smaller testable methods and frankly your code would be worse for it.

    • This method also suffers a similiar problem to the Repository Pattern solution, in that by excluding Entity framework from the equation you aren't able to test that no exceptions are occuring in the committing of your changes after you make a change to your entities.

 

So what is a good idea?

I believe a package called "Effort" is the best solution. Effort creates a mock of your database in memory, this means Entity Framework performs exactly the same as it does in production systems but without actually touching your database. You will also get all of the benefits of Entity Framework like the linking of Entities and automatic population of keys.

I have only recently started using Effort, but so far it has proved incredibly good, although difficult to implement initially, this post would help you to reduce that pain though.

Essentially you add Effort via the NUGET Package Manager, setup a little bit of code to initialise it in your Unit Tests project and you are good to go. You can use Effort with Visual Studio's Test Solution in addition to others like NUnit. You can then use the context directly in your normal code and your Unit Tests cover everything that your production code uses.

One extra bonus to this package, is that if you haven't been thinking about Unit Testing until now, it won't involve a large scale refactoring of your existing code base to implement.

One caveat to note though is that you should remember not to test Entity Framework functionality specifically, but you can be sure that no exceptions are propagating out of your methods.

 

So how do you set it up?

Create a new project for your Unit Tests if you don't have one already. You can just add a "Unit Test Project" in your language of choice. The convention for mine was to use the name of the project I am testing and add ".Tests" at the end to denote that it was Unit Tests.

  • Install "Effort.EF6" from the Nuget Package Manager, make sure to get the right one, there is a package called "Effort" which is the same technology, but doesn't work with Entity Framework 6.

Create a Unit Test Class with an initialisation method like below. Make sure to add the right attributes to the class as seen in the screenshot below.

 

The Initialise() method is where Effort does its work, first of all you create an object scoped to the Class that reflects your Entity Framework Context, and then you assign it a reference within the Initialise method using the Effort Connection Factory.

When you do this Effort returns the EF Context for you to inject into your service layer, It is exactly the same object as it would be in production so your services don't need to change. The only difference is that all of your changes are saved in memory, not to your database.

The next part of the setup caused me several hours of confusion but was simple enough in the end, in order to use Effort; your Entity Framework DBContext needs to have a constructor allowing for a DbConnection, so you need to go away now and add that.


 

You don't want to remove the existing constructor, just add this one (with the DbConnection parameter) in addition to that.

This is important because by default Entity Framework creates the DBContext with no parameters, therefore if you use a Dependency Injection tool like StructureMap it will cease to work if you do not tell it how to register your DBContext. Effort uses the constructor with the DbConnection parameter, and your website uses the constructor with no parameters as it pulls your connection details from your configuration file.

To make this work you need to tell StructureMap which constructor to use, if you don't StructureMap will always try to use the constructor with the DbConnection parameter because it picks the greediest of all constructors until told otherwise.

You can tell StructureMap which constructor to use by doing the below...


If you have done all of that, you should now be able to write Unit Tests without fear of your database being contaminated, and your website should operate as normal!

For those new to Effort.EF6, if you setup your initialisation method the same way I have, it will give you a clean database (In memory of course) for every individual unit test

 

An example Unit Test I wrote is displayed below for information purposes.


 

Let me know in the comments if this guide helped, or if you ran into any problems. 

Thanks, Tom.

 

You need to Login or Register to comment.


No Comments Left Yet

Why not add your own comments or thoughts to get the chat started?

Gallery Image Gallery Image Gallery Image
Portal CMS

Have you seen PortalCMS?

PortalCMS is my proudest personal project to date, it has taken a long time and a lot of effort, but its now more than I ever expected it to be. Find out why!

Blog

What am I working on these days?

This post is just a brief update about what I am spending my development time working on recently.

Technology

Introducing LogBook

I recently wanted to add some basic logging into an MVC Web Project, but all of the big offerings like Elmah and Log4Net are too bloated, so I decided to write a minimalistic logging tool of my own.

Portal CMS

Navigation Improvements in Portal CMS

I recently developed some awesome new ways to manage the navigation in your Portal CMS website. Check out what is new in this post.

Portal CMS

Portal CMS - Developing the Theme Manager

This post takes a look at the development so far on a major feature for Portal CMS. The abilty to theme your websites easily to make them even more unique.

Portal CMS

Portal CMS - Release 1.0

The first stable release of Portal CMS is now available, so its a great time to start using Portal CMS for your own website or blog.

Portal CMS

Portal CMS Demo Website Now Available

I wanted to make it as easy as possible to try out Portal CMS. So I have setup a demo website you can login to and try it out!

Portal CMS

User Experience Improvements to the Portal CMS Page Builder

We recently made some changes to the Page Builder in Portal CMS to make it easier and quicker to use. Learn more about what has changed inside this post.

Blog

Summer Holiday in Thassos, Greece

I just returned from a holiday in Thassos in Greece, so I wanted to post up some photo's to show what I got up too!

Portal CMS

Editor Support Added to Portal CMS

Often you want to setup a website for somebody but you want to limit how much they can affect it without you, maybe you want to be responsible for the site, but they want to create content. Now you can in Portal CMS.

Technology

What is SendGrid?

As somebody who develops quite a lot of websites, I find that most of the time I tend to use a lot of the same technologies and services. A lesser known service which I have come to love is called SendGrid, heres why I love it.

Portal CMS

Inline Editing in Portal CMS

I recently releasd a huge change to the Portal CMS technology I have been working on. The ability to change content just like you do offline in Microsoft Office. No need to save changed, nor wait for changes to be made.

Tips and Tricks

How to setup a Web App on Microsoft Azure

A how to guide to creating a Web App on Microsoft Azure, deploying it using Continuous Deployment and hooking it up to a database.

Portal CMS

Portal CMS - Promotional Website

I decided to make a standalone website for Portal CMS; the technology I wrote to sit behind this website and many others. Why not take a look and see what its about?

Blog

Website Relaunch

Welcome to my personal website. I am just in the process of relaunching it under my new technology called Portal CMS.

Tips and Tricks

Cost Effective Email Hosting for Custom Domains (Migrated)

This article takes a look at options for setting up multiple email accounts for multiple custom domains.

Portal CMS

Portal CMS - Page Builder Demo

Portal CMS is my latest technology, this article shows a video demonstration of the new technology in action.

Technology

Windows 10 - Initial Reaction (Migrated)

This article covers my initial reaction to Windows 10 after using it on my main computer for a few days.

Technology

Windows 10 - Coming soon (Migrated)

A brief look at the upcoming Windows 10 release and a look at the new features in the update.