HttpContext.Current is null when unit test

12,431

Solution 1

During unit tests HttpContext is always null as it is usually populate by IIS. You have a few options around this.

Sure, you could mock the HttpContext, (which you shouldn't really do - Don't mock HttpContext!!!! He doesn't like to be mocked!),. You should really try to stay away from tight coupling with HttpContext all over your code. Try constraining it to one central area (SRP);

Instead figure out what is the functionality you would like to achieve and design an abstraction around that. This will allow for your code to be more testable as it is not so tightly coupled to HttpContext.

Based on your example you are looking to access header values. This is just an example of how to change your thinking when it comes to using HttpContext.

Your original example has this

var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];

When you are looking for something like this

var testName = myService.GetOsType();

Well then create a service that provides that

public interface IHeaderService {
    string GetOsType();
}

which could have a concrete implementation like

public class MyHeaderService : IHeaderService {

    public string GetOsType() {
        var request = HttpContext.Current.Request;
        var testName = request.Headers.GetValues("OS Type")[0];
        return testName;
    }
}

Now in your controller you can have your abstraction instead of having tight coupling to HttpContext

public class MyApiController : ApiController {
    IHeaderService myservice;
    public MyApiController(IHeaderService headers) {
        myservice = headers;
    }

    public IHttpActionResult Post([FromBody]TestDTO model) {    
        var testName = myService.GetOsType();
        // more code

    }    
}

You can later inject your concrete type to get the functionality you want.

For testing you then swap dependencies to run your test.

If the method under test is your Post() method you can create a fake dependency or use a mocking framework

[TestClass]
public class MyTestClass {

    public class MyFakeHeaderService : IHeaderService {
        string os;
        public MyFakeHeaderService(string os) {
            this.os = os;
        }

        public string GetOsType() {
            return os;
        }
    }

    [TestMethod]
    public void TestPostMethod() {
        //Arrange
        IHeaderService headers = new MyFakeHeaderService("FAKE OS TYPE");
        var sut = new MyApiController(headers);
        var model = new TestDTO();

        //Act
        sut.Post(model);

        //Assert
        //.....
    }
}

Solution 2

This is by design and it's always null. But there is a FakeHttpContext project on Nuget that simply you can use it.

To install FakeHttpContext, run the following command in the Package Manager Console (PMC)

Install-Package FakeHttpContext 

And then use it like this:

using (new FakeHttpContext())
{
HttpContext.Current.Session["mySession"] = "This is a test";       
}

Visit https://www.nuget.org/packages/FakeHttpContext to install the package

See examples on Github: https://github.com/vadimzozulya/FakeHttpContext#examples

Hope this will help :)

Share:
12,431
simbada
Author by

simbada

Updated on June 13, 2022

Comments

  • simbada
    simbada almost 2 years

    I have following web Api controller method.

    When I run this code through web, HttpContext.Current is never null and give desired value.

    public override void Post([FromBody]TestDTO model)
    {
    
        var request = HttpContext.Current.Request;
        var testName = request.Headers.GetValues("OS Type")[0];
        // more code
    
    }
    

    However, when I call this method from Unit Test, HttpContext.Current is always null.

    How do i fix it?

  • simbada
    simbada almost 8 years
    Excellent answer and explanation. I understand your point and can resolve my issue. Thanks
  • jeubank12
    jeubank12 over 5 years
    A great reference from 2014: docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/… This has some other essential details such as Inversion of Control which will allow you to call your custom context class during controller instantiation.
  • nbstrat
    nbstrat almost 2 years
    Excellent answer and was able to take your explanation and apply it to my own test case that required using HttpContext.Current.Request.Cookies.