Unit Testing OData Web API/Entity Framework Applications

The cost of fixing bugs is lower if found early in the software development cycle. Unit tests greatly reduce this cost by pushing quality upstream. This helps prevent regression bugs and when coupled with TDD approach, provides a solid foundation for a complete test suite. Furthermore, teams are striving to push code into production more frequently and with higher quality. In order to flourish in this DevOps space, it is imperative to have a pipeline of solid automated tests. Traditionally, unit tests have been written for a class library projects or middle tier/business logic projects.

In this blog post, I will demonstrate how to easily unit test an OData based Web API service which is consuming data from SQL DB using Entity Framework. The goal is to write unit tests which stub out the actual DB calls. We will make use of faking the DB Context and using a common DI pattern of construction injection. The result is a highly testable maintainable and cohesive codebase.


Create the ASP.NET Web Application

First, open Visual Studio VS 2013, create an ASP.Net Web Application, choose MVC and Web API template and check the Add Unit Tests checkbox.

imageimage

 

Create the DB

Next, create a SQL Database as the backend for this project. Use SQL Server Edition of your choice. I am using SQL Server 2014 for this post. We will use Entity Framework(EF 6.0.0.0) to connect to this DB.

Let the DB name be ODataDB

image

Next up, create a Table in the database named Application with following properties.

Create the Application Table

image

 

Reverse Engineer Code First from the DB

Right Click on the Web API project we created to reverse engineer code from the database. You will need to install Visual Studio Entity framework extensions.
Make sure Entity Framework dll’s are referenced in the project.

image

We now have Application Map.cs and ODataDBContext.cs created and mapping created.

 

Create ODataController

Next up, install Web API OData Libraries from Nuget for the Web API project. I am using the latest version of ASP.Net Web API2.2 for OData v1-3

image

Now let’s create ODataController based on Entity Framework and call it Application Controller.

image

We will use ApplicationMap and ODataDBContext for Model and Data Context class respectively.

image

Now that Application Controller is created and we have our Get/Post/Put operations in place in the controller class.

image

Click F5, and the OData Service is up and running!

image

Create Unit Test for the Application Controller

Now that the application is running, we want to write unit tests for it.

First and foremost, we need to Fake Out the DB Context in our application. Instead of using the ODataDBContext, we will use FakeDBContext. In order to do that we first need to create an interface for ODataDBContext. We will call it IODataDBContext and have ODataDBContext implement from it.

Create Interface IODataDBContext

image

 

image

Implement IODataDBContext from ODataDBContext

image

 

Run the application to see everything works like before. Now that the IODataDBContext is in place, let’s create FakeDBContext in the Unit Test Project.

Unit Test Project Plumbing

Add the following to the Unit Test Project.

  • Add FakeODataDBContext to the unit test project. Ensure that FakeODataDBContext implements the IODataDBContext Interface.
  • Add Entity framework dll to the references.
  • Add System.Web.Http dll to the references.
  • Add System.Web.Http.OData dll to the references.
  • Add FakeDBSet class to the project.

image

image

Notice the constructor in the FakeODateDBContext, it has a method called GetApp(), this method is used to create the Fake Application object which is returned to the Unit test when calling the ODataController for Application.

Below is the code for GetApp(), Here we are using the FakeDbSet to create a Fake Application Object in memory for the purposes of the Unit Test.

image

Before we start writing Unit Tests, we need to tweak the controller code to expose the ODataDBContext object as a parameter. This is classic case of constructor dependency injection which would make the code testable.

image

Now, let’s write the Unit Test for the Application Controller. Here is the Code for the unit test. The unit test  is a  Visual Studio Unit Test.

image

As you see above, we have successfully written a Unit Test for the ODataController Api. The above unit test will exercise the code paths of your controller code and also execute any logic inside it without having to make the actual Database call. The FakeDBContext lets you get/set  data in memory and disposes it once the unit test exits.

You can potentially create Unit Tests for all your Controller methods(Get,Post.Put,Delete) across all your application and ensure very high Code Coverage and a highly testable and maintainable application.

Hopefully this post helps you start writing Unit tests for ODataController Services using Entity Framework.


Comments

  • Anonymous
    May 18, 2015
    What is application map ? modelBuilder.Configurations.Add(new ApplicationMap());

  • Anonymous
    May 18, 2015
    Application Map is the EF map file e.g.would look something like this; public ApplicationMap()        {            // Primary Key            this.HasKey(t => t.AppId);            // Properties            this.Property(t => t.AppId)                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);            this.Property(t => t.AppName)                .IsRequired()                .HasMaxLength(50);            // Table & Column Mappings            this.ToTable("Application");            this.Property(t => t.AppId).HasColumnName("AppId");            this.Property(t => t.AppName).HasColumnName("AppName");            this.Property(t => t.IsActive).HasColumnName("IsActive");        } if you reverse engineer code using the EF tools - www.microsoft.com/.../details.aspx, you would get the code created for you.

  • Anonymous
    May 26, 2015
    Can you share the FakeDbSet implementation?

  • Anonymous
    May 27, 2015
    www.nuget.org/.../FakeDbSet gist.github.com/.../6595426