Difference between HttpContext and HttpContextWrapper in terms of Unit Testing and in terms of Web Forms and MVC

10,323

I heard that it's useful in Unit Testing in comparing with Web Forms. but how it's useful ?

Let's take an example of an ASP.NET MVC controller action which is adding a cookie to the response:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var cookie = new HttpCookie("foo", "bar");
        this.Response.Cookies.Add(cookie);
        return View();
    }
}

Notice the Response property over there. It's an HttpResponseBase. So we can mock it in a unit test:

public class HttpResponseMock: HttpResponseBase
{
    private HttpCookieCollection cookies;
    public override HttpCookieCollection Cookies
    {
        get
        {
            if (this.cookies == null)
            {
                this.cookies = new HttpCookieCollection();
            }

            return this.cookies;
        }
    }
}

public class HttpContextMock: HttpContextBase
{
    private HttpResponseBase response;

    public override HttpResponseBase Response
    {
        get 
        {
            if (this.response == null)
            {
                this.response = new HttpResponseMock();
            }
            return this.response;
        }
    }
}

and now we could write a unit test:

// arrange
var sut = new HomeController();
var httpContext = new HttpContextMock();
sut.ControllerContext = new ControllerContext(httpContext, new RouteData(), sut);

// act
var actual = sut.Index();

// assert
Assert.AreEqual("bar", sut.Response.Cookies["foo"].Value);

And since all members are virtual we could use a mocking framework which would avoid us the need to write those mock classes for the unit test. For example with NSubstitute here's how the test might look:

// arrange
var sut = new HomeController();
var context = Substitute.For<HttpContextBase>();
var response = Substitute.For<HttpResponseBase>();
var cookies = new HttpCookieCollection();
context.Response.Returns(response);
context.Response.Cookies.Returns(cookies);
sut.ControllerContext = new ControllerContext(context, new RouteData(), sut);

// act
var actual = sut.Index();

// assert
Assert.AreEqual("bar", sut.Response.Cookies["foo"].Value);

Now let's take a WebForm:

protected void Page_Load(object sender, EventArgs)
{
    var cookie = new HttpCookie("foo", "bar");
    this.Response.Cookies.Add(cookie);
}

In this case the Response property is the concrete HttpResponse. So you are busted. Impossible to unit test in isolation.

Share:
10,323
Peter Burns
Author by

Peter Burns

Stack Overflow Valued Associate #00001 Wondering how our software development process works? Take a look! Find me on twitter, or read my blog. Don't say I didn't warn you because I totally did. However, I no longer work at Stack Exchange, Inc. I'll miss you all. Well, some of you, anyway. :)

Updated on September 25, 2022

Comments

  • Peter Burns
    Peter Burns over 1 year

    I know the difference between HttpContext and HttpContextWrapper is below...

    HttpContext

    This is the vintage asp.net context. The problem with this is that it has no base class and isn't virtual, and hence is unusable for testing (cannot mock it). It's recommended to not pass it around as function arguments, instead pass around variables of type HttpContextBase.

    HttpContextBase

    This is the (new to c# 3.5) replacement to HttpContext. Since it is abstract, it is now mockable. The idea is that your functions that expect to be passed a context should expect to receive one of these. It is concretely implemented by HttpContextWrapper

    HttpContextWrapper

    Also new in C# 3.5 - this is the concrete implementation of HttpContextBase. To create one of these in a normal webpage, use new HttpContextWrapper(HttpContext.Current).

    The idea is that to make your code unit-testable, you declare all your variables and function parameters to be of type HttpContextBase, and use an IOC framework eg Castle Windsor to get it injected. In normal code, castle is to inject the equivalent of 'new HttpContextWrapper (HttpContext.Current)', whereas in test code you're to be given a mock of HttpContextBase.

    But I am not aware about its real use. I heard that it's useful in Unit Testing in comparing with Web Forms. but how it's useful ?


    I also know that we can use it to execute the controller and Action as mentioned here