Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / unit-testing

Unit Testing MVC Web API

4.33/5 (6 votes)
17 Apr 2016CPOL1 min read 12.2K  
Make MVC Web API code unit testable from controller

Introduction

To make a Web API unit testable, we have to initialize the dependent interfaces via the controller’s constructor. The challenge with MVC Web API is that when an HttpRequest is made, the IHttpControllerActivator class tries to initialize the controller based on which controller has been selected and passed on by HttpControllerDispatcher class. By default, IHttpControllerActivator looks for a parameter-less constructor. Hence, if we are using dependency injection (DI) in our Web API, we usually get errors that look like this:

C#
{  
   "Message":"An error has occurred.",
   "ExceptionMessage":"An error occurred when trying to 
   create a controller of type <your controller name>. 
   Make sure that the controller has a parameterless public constructor.",
   "ExceptionType":"System.InvalidOperationException",
   "StackTrace":"   
   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create
   (HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, 
   Type controllerType)\r\n   
   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController
   (HttpRequestMessage request)\r\n   
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
   "InnerException":{  
      "Message":"An error has occurred.",
      "ExceptionMessage":"Type <controller type> does not have a default constructor",
      "ExceptionType":"System.ArgumentException",
      "StackTrace":"   at System.Linq.Expressions.Expression.New(Type type)\r\n   
      at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n   
      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator
      (HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   
      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create
      (HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, 
      Type controllerType)"
   }
}

Solution

To solve this problem and still have a unit testable code written using DI, we have to register a dependency resolver with our HttpConfiguration class.

The Code

In the WebApiConfig.cs file, where all the configurations are registered with our HttpConfiguration class, we have to assign our UnityContainer that holds all the dependency resolution rules, to the DependencyResolver property of HttpConfiguration instance.

C#
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var container = <Register all dependencies here>;
        config.DependencyResolver = new UnityResolver(container);

        // Web API configuration and services


        // Web API routes
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

    }
}

The moment this registration of dependency resolver is done, the framework knows how to resolve the interfaces that are needed in the controller’s constructor, and hence can get through the GetInstanceOrActivator method successfully.

Point of Interest

This kind of registrations and DI hooking helps us start the unit testing right from the controller methods as compared to testing only the business libraries separately. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)