65.9K
CodeProject is changing. Read more.
Home

Unit Testing MVC Web API

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (6 votes)

Apr 18, 2016

CPOL

1 min read

viewsIcon

12190

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:

{  
   "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.

    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.