Bob
Bob

Reputation: 4386

.NET: how can I unit test this method?

(Similar to .NET how to fudge the HttpContext object!)

I have a method that I want to test:

    public void MyMethod()
    {
        if (HttpContext.Current.Application["myValue"] != null)
            Console.WriteLine("Boo!");
    }

How can I write a test WITHOUT refactoring the method so that the Console.WriteLine is hit?

I tried with:

        TextWriter tw = new StringWriter();
        HttpWorkerRequest wr = new SimpleWorkerRequest("/webapp", @"path...", "logon.asp", "", tw);
        HttpContext.Current = new HttpContext(wr);
        HttpContext.Current.Application.Add("KeyValue", "myValue");
        MyMethod();

but HttpContext.Current.Application.count is always zero, I cannot add values to it!

Upvotes: 3

Views: 2210

Answers (4)

Grzegorz Smulko
Grzegorz Smulko

Reputation: 2823

You can use HttpSimulator class from www.koders.com - Subtext.TestLibrary

Just invoking

new Subtext.TestLibrary.HttpSimulator().SimulateRequest();

sets your HttpContext properly, so you can also add values to Application dictionary.

As Jeff said, it sets HttpApplicationFactory._theApplicationFactory._state using Reflection as below, but you don't have to bother about it, actually.

Type appFactoryType = Type.GetType("System.Web.HttpApplicationFactory, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
object appFactory = ReflectionHelper.GetStaticFieldValue<object>("_theApplicationFactory", appFactoryType);
ReflectionHelper.SetPrivateInstanceFieldValue("_state", appFactory, HttpContext.Current.Application);

Upvotes: 4

Dan Bryant
Dan Bryant

Reputation: 27515

If you're specifically prohibited from refactoring the method and are also required to test it, you can use a detouring system, such as Moles or TypeMock Isolator, to completely detour the static and HttpContext calls. This can get a bit ugly, however and it's much preferable to perform refactoring on the original code.


Sequence of detoured mocks would be:

  1. Detour HttpContext.Current to return a HttpContext detour stub (your own implementation that complies with the HttpContext class interface, but looks exactly like HttpContext to the tested code.)

  2. In your HttpContext detour stub, mock Application["myValue"] to return your desired value (either null or non-null in this case.) This will probably require creating a detour class for the return value of Application.

  3. Now you can configure the detours and run your method. The calls to HttpContext.Current and the HttpContext methods will be rerouted through the Profiling API to your detour stubs.

Upvotes: 3

Jeff Sternal
Jeff Sternal

Reputation: 48673

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.

Upvotes: 1

jason
jason

Reputation: 241769

The thing is you should refactor this method so that it's easier to test! To properly test this you want to mock HttpContext (here's one example as to how: How to use Rhino Mocks to Mock an HttpContext.Application).

Upvotes: 4

Related Questions