Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing a WebAPI2 controller method with a header value

I'd like to "unit" test a method on my WebAPI contoller.

This method relies on a header being sent with it.

So

HttpContext.Current.Request.Headers["name"]

needs to have a value in the method body.

What is the best way of doing this? I thought I'd be able to set the ControllerContext which would populate HttpContext, but can't get it working.

I'd prefer not to use a mocking framework or any other third party tools, as my understanding is that WebAPI2 plays nicely with this use case.

I'm happy to set HttpContext.Current if that's the best way.

like image 510
Ev. Avatar asked May 07 '14 03:05

Ev.


2 Answers

I would suggest it.
While you create your private controller objects set these settings at that time.

    private HomeController createHomeController()
    {
        var httpContext = new DefaultHttpContext();
        httpContext.Request.Headers["Key"] = "value123";
        var controllerContext = new ControllerContext
        {
            HttpContext = httpContext
        };
          
        return new HomeController()
        {
            ControllerContext = controllerContext
        };
    }
like image 127
Davinder Singh Avatar answered Oct 09 '22 17:10

Davinder Singh


Sometimes, you have little/no control of the code you are writing tests for. If it's already been designed to use HttpContext.Current, and you keep getting "Operation is not supported on this platform." errors like i struggled with, this will help.

public static class NameValueCollectionExtensions
{
    public static NameValueCollection AddValue(this NameValueCollection headers, string key, string value)
    {
        Type t = headers.GetType();
        t.InvokeMember("MakeReadWrite", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, null);
        t.InvokeMember("InvalidateCachedArrays", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, null);
        t.InvokeMember("BaseAdd", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, new object[] { key, new System.Collections.ArrayList() { value } });
        t.InvokeMember("MakeReadOnly", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, null);
        return headers;
    }
}

With that class in the same namespace, you can add the headers like:

HttpContext.Current.Request.Headers.AddValue("header_key", "header_value");

Of course, if you don't like extension methods, you could always use a wrapper method instead.

I hope this helps someone.

like image 21
mykeels Avatar answered Oct 09 '22 16:10

mykeels