Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing post controller .NET Web Api

I don't have much experience with .NET Web Api, but i've been working with it a while now, following John Papa's SPA application tutorial on Pluralsight. The application works fine, but the thing i'm struggling with now, is unit testing POST-controllers.

I have followed this incredible guide on how to unit test web api controllers. The only problem for me is when it comes to test the POST method.

My controller looks like this:

    [ActionName("course")]
    public HttpResponseMessage Post(Course course)
    {
        if (course == null)
            throw new HttpResponseException(HttpStatusCode.NotAcceptable);
        try
        {
            Uow.Courses.Add(course);
            Uow.commit();
        }
        catch (Exception)
        {
            throw new HttpResponseException(HttpStatusCode.InternalServerError);
        }

        var response = Request.CreateResponse(HttpStatusCode.Created, course);

        string uri = Url.Link(routeName: "ControllerActionAndId", 
        routeValues: new { id = course.Id });

        response.Headers.Location = new Uri(uri);

        return response;
    }

And my unit test looks like this:

   [Test]
    public void PostShouldReturnHttpResponse()
    {
        var populatedPostController = new CoursesController(new TestUOW());

        SetupPostControllerForTest(populatedPostController);

        var course = new Course
        {
            Id = 12,
            Author = new UserProfile()
            {
                Firstname = "John",
                Lastname = "Johnson",
            },
            Description = "Testcourse",
            Title = "Test Title"
        };

          var responses = populatedPostController.Post(course);

          ObjectContent content = responses.Content as ObjectContent;
          Course result = (Course)content.Value;
          Assert.AreSame(result, course);
    }

With the help function:

    public static void SetupPostControllerForTest(ApiController controller)
    {

        var config = new HttpConfiguration();
        var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/courses/course");
        var route = config.Routes.MapHttpRoute(
            name: "ControllerActionAndId",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: null,
            constraints: new { id = @"^\d+$" }
        );

        var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "courses" }, { "action", "course" } });

        controller.ControllerContext = new HttpControllerContext(config, routeData, request);
        controller.Request = request;
        controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
    }

When i debug the unit test, it seems to fail at:

        string uri = Url.Link(routeName: "ControllerActionAndId", 
        routeValues: new { id = course.Id });

        response.Headers.Location = new Uri(uri); //Exception because uri = null

It seems like the Url.Link can't find the route.

I tried this guide aswell, but i really want the example i have above to work.

Am i missing something really basic here?

like image 330
Are Almaas Avatar asked Mar 14 '13 13:03

Are Almaas


1 Answers

Yes, you are missing the one line in the configuration as Nemesv mentioned.

controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData

As you can see, configuring a controller just for using the UrlHelper is extremely complex. I tend to avoid the use of UrlHelper in the controller classes for that reason. I usually introduce an external dependency to make testing easier like an IUrlHelper, which allows me to mock the behavior in an unit test.

public interface IUrlHelper
    {
        string Link(string routeName, object routeValues);
        string Route(string routeName, object routeValues);
    }

    public class UrlHelperWrapper : IUrlHelper
    {
        UrlHelper helper;

        public UrlHelperWrapper(UrlHelper helper)
        {
            this.helper = helper;
        }

        public string Link(string routeName, object routeValues)
        {
            return this.helper.Link(routeName, routeValues);
        }

        public string Route(string routeName, object routeValues)
        {
            return this.helper.Route(routeName, routeValues);
        }
    }

I inject this UrlHelperWraper in the real Web API, and a mock of the IUrlHelper interface in the tests. By doing that, you don't need all that complex configuration with the routes.

Regards, Pablo.

like image 139
Pablo Cibraro Avatar answered Nov 02 '22 11:11

Pablo Cibraro