HttpContext.Current is null when unit test

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 :)