Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting HttpContext.Current.Application key in unit tests

I have a method which internally uses the static HttpContext.Current.Application to store a key-value pair and retrieve it throughout the application afterwards.

Now, what I want to do is to unit test that method. What I currently have is this:

private const string Foo = "foobar";

[TestInitialize]
public void InitializeContext()
{
    HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
    HttpContext.Current.Application["fooKey"] = Foo;
}

[TestCleanup]
public void DisposeContext()
{
    HttpContext.Current = null;
}

All good, but when I try to cast that value in the TestMethod, the value is null.

var fooValue = (string)HttpContext.Current.Application["fooKey"];

Obviously, the value is null in the method which I'm testing as well.

What I tried so far is to mock the context - didn't work as well. Then I saw the fake HTTP context solution on SO, still doesn't work. I even tried accepting HttpApplicationStateBase/ HttpApplicationStateWrapper and working through them, but it becomes a mess and I feel that there's a lot simpler solution than that.

like image 581
arnaudoff Avatar asked Sep 25 '22 07:09

arnaudoff


1 Answers

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.

like image 61
arnaudoff Avatar answered Nov 15 '22 07:11

arnaudoff