Mock Httpcontext.Current in Test Init Method

Mock HttpContext.Current in Test Init Method

HttpContext.Current returns an instance of System.Web.HttpContext, which does not extend System.Web.HttpContextBase. HttpContextBase was added later to address HttpContext being difficult to mock. The two classes are basically unrelated (HttpContextWrapper is used as an adapter between them).

Fortunately, HttpContext itself is fakeable just enough for you do replace the IPrincipal (User) and IIdentity.

The following code runs as expected, even in a console application:

HttpContext.Current = new HttpContext(
new HttpRequest("", "http://tempuri.org", ""),
new HttpResponse(new StringWriter())
);

// User is logged in
HttpContext.Current.User = new GenericPrincipal(
new GenericIdentity("username"),
new string[0]
);

// User is logged out
HttpContext.Current.User = new GenericPrincipal(
new GenericIdentity(String.Empty),
new string[0]
);

How do I unit test HttpContext.Current.Request.LogonUserIdentity.Name ?

I spent a lot of time trying to mock HttpContext or HttpContextBase, then trying to shim with fakes WindowsIdentity class or HttpRequest.LogonUserIdentity property.
Nothing works - you don't need completely mocked HttpContext because you want see real responses, not your mock set ups returned.
Shims are just not generating for WindowsIdentity class ("due to internal limitations") and for LogonUserIdentity property (no reason given in fakes messages, it's just not there).

The best approach how to get testable HttpContext with request and response is described here:
http://jonlanceley.blogspot.com/2015/08/unit-testing-part-2-faking-httpcontext.html

I was able to override LogonUserIdentity property in my fake request wrapper and set there whatever I need.

How to create unit test with HttpContext for authorization inside a method?

HttpContext.Current is static and can be assigned:

HttpContext.Current = new HttpContext(
new HttpRequest("", "http://tempuri.org", ""),
new HttpResponse(new StringWriter())
);

// User is logged in
HttpContext.Current.User = new GenericPrincipal(
new GenericIdentity("username"),
new string[0]
);

// User is logged out
HttpContext.Current.User = new GenericPrincipal(
new GenericIdentity(String.Empty),
new string[0]
);

Code from Mock HttpContext.Current in Test Init Method

Setting HttpContext.Current.Application key in unit tests

What I ended up doing is using this amazing library. For those who wonder why nothing worked, this StackOverflow question explains a similar problem (strange how I couldn't find it before asking).

According to Jeff Sternal's answer:

HttpContext.Application is supplied by a private singleton that you can't access normally.

You may be able to set this via reflection, but I personally wouldn't even bother.

Instead you should isolate your testable code from global state like HttpContext.Current: just pass the value you're looking for into the method you want to test.

You can see the problem clearly looking at the code in Reflector (or in the .NET source if you've downloaded that): the HttpContext.Application get accessor returns a new HttpApplicationState instance every time you call it unless something (like the ASP.NET framework) sets HttpApplicationFactory._theApplicationFactory._state.

Eventually, I ended up doing something like:

using (HttpSimulator simulator = new HttpSimulator())
{
simulator.SimulateRequest(new Uri("http://localhost/"));
HttpContext.Current.Application.Add("fooKey", Foo);
this.httpContext = HttpContext.Current;
}

And then passed the saved reference to my method.

Setting HttpContext.Current.Session in a unit test

We had to mock HttpContext by using a HttpContextManager and calling the factory from within our application as well as the Unit Tests

public class HttpContextManager 
{
private static HttpContextBase m_context;
public static HttpContextBase Current
{
get
{
if (m_context != null)
return m_context;

if (HttpContext.Current == null)
throw new InvalidOperationException("HttpContext not available");

return new HttpContextWrapper(HttpContext.Current);
}
}

public static void SetCurrentContext(HttpContextBase context)
{
m_context = context;
}
}

You would then replace any calls to HttpContext.Current with HttpContextManager.Current and have access to the same methods. Then when you're testing, you can also access the HttpContextManager and mock your expectations

This is an example using Moq:

private HttpContextBase GetMockedHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
var urlHelper = new Mock<UrlHelper>();

var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
var requestContext = new Mock<RequestContext>();
requestContext.Setup(x => x.HttpContext).Returns(context.Object);
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
context.Setup(ctx => ctx.User).Returns(user.Object);
user.Setup(ctx => ctx.Identity).Returns(identity.Object);
identity.Setup(id => id.IsAuthenticated).Returns(true);
identity.Setup(id => id.Name).Returns("test");
request.Setup(req => req.Url).Returns(new Uri("http://www.google.com"));
request.Setup(req => req.RequestContext).Returns(requestContext.Object);
requestContext.Setup(x => x.RouteData).Returns(new RouteData());
request.SetupGet(req => req.Headers).Returns(new NameValueCollection());

return context.Object;
}

and then to use it within your unit tests, I call this within my Test Init method

HttpContextManager.SetCurrentContext(GetMockedHttpContext());

you can then, in the above method add the expected results from Session that you're expecting to be available to your web service.

How do I unit test a class that depends on HttpContext.Current and Sitecore.Context?

You would need to create a mock HTTPContext and inject it into the method for the test. (You probably need to mock quite a few other objects too, since the method has several dependencies.)

Then, after the method has run, assert that the the response in the context is as you want it.

See details here: Mock HttpContext.Current in Test Init Method



Related Topics



Leave a reply



Submit