6

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?

2
  • 1
    Try to add the following line at the end of your SetupPostControllerForTest method controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData; Commented Mar 14, 2013 at 13:46
  • Yep, it works now! That's what happens when you're tired.. Thanks! Commented Mar 14, 2013 at 14:20

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow. How could i miss that :/. Seems like a more clean way to handle the UrlHelper. Nice one, thanks!
Hi @Pablo Cibraro would you please be able to give some live example, I am writing my unit tests first time for web api and to create them in most optimized way I landed here. I din't understand how you are utilizing URL helpers and what there in the question which you have eliminated using URl Helpers. Any Help would be greatly appreciated

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.