views:

469

answers:

1

I've been going through the process of cleaning up our controller code to make each action as testable. Generally speaking, this hasn't been too difficult--where we have opportunity to use a fixed object, like say FormsAuthentication, we generally introduce some form of wrapper as appropriate and be on our merry way.

For reasons not particularly germaine to this conversation, when it came to dealing with usage of HttpContext, we decided to use the newly created HttpContextWrapper class rather than inventing something homegrown. One thing we did introduce was the ability to swap in a HttpContextWrapper (like say, for unit testing). This was wholly inspired by the way Oren Eini handles unit testing with DateTimes (see article, a pattern we also use)

public static class FooHttpContext
{
    public static Func<HttpContextWrapper> Current = () 
         => new HttpContextWrapper(HttpContext.Current);

    public static void Reset()
    {
        Current = () => new HttpContextWrapper(HttpContext.Current);
    }
}

Nothing particularly fancy. And it works just fine in our controller code. The kicker came when we go to write unit tests. We're using Moq as our mocking framework, but alas

var context = new Mock<HttpContextWrapper>() 

breaks since HttpContextWrapper doesn't have a parameterless ctor. And what does it take as a ctor parameter? A HttpContext object. So I find myself in a catch 22.

I'm using the prescribed way to decouple HttpContext--but I can't mock a value in because the original HttpContext object was sealed and therefore difficult to test. I can map HttpContextBase, which both derive from--but that doesn't really get me what I'm after. Am I just missing the point somewhere with regard to HttpContextWrapper?

Edit to clarify intent

We found ways to solve the problem--but I guess the ultimate question we're walking away with is what value HttpContextWrapper brings to the table? I don't doubt somewhere someone totally had an a-ha! moment with it, but it just doesn't come to me. Most postings I see here discuss it in terms of testability--but my own experience has led me to believe that it didn't bring much in that context. Unless we're doing it wrong. (Wholly possible).

+3  A: 

You should be using the abstract HttpContextBase which is much easier to mock instead of HttpContextWrapper.

public static Func<HttpContextBase> Current = 
    () => new HttpContextWrapper(HttpContext.Current);

And in your unit test:

SomeClass.Current = MockHttpContextBase(); // Sorry I don't know the syntax for Moq
Darin Dimitrov
You're absolutely right--and what we ultimately did...but my question more I guess was about what Wrapper really brings to the table--let me edit for clarity.
bakasan
`HttpContextWrapper` is not meant to be an abstraction but a concrete implementation of `HttpContextBase`. I guess it's value is that it hides some static and internal methods of `HttpContext`.
Darin Dimitrov
`HttpContextWrapper` implements the (mockable) `HttpContextBase` by forwarding calls to the ASP.NET-vintage `HttpContext`. It's a wart to get around the fact that `HttpContext` isn't mockable.
Roger Lipscombe
I guess I just question using the wrapper vs just using the base--I presumed it was more of an abstraction than a concrete mechanism given it lives inside System.Web.Abstractions. Would still love to hear about any a-ha! moments where the wrapper was the absolute silver bullet, but otherwise I'll mark this the answer.
bakasan