Introduction:
I think this sentence now become very familiar to ASP.NET MVC developers that "ASP.NET MVC is designed with testability in mind". But what ASP.NET MVC team did for making applications build with ASP.NET MVC become easily testable? Understanding this is also very important because it gives you some help when designing custom classes. So in this article i will discuss some abstract classes provided by ASP.NET MVC team for the various ASP.NET intrinsic objects, including HttpContext, HttpRequest, and HttpResponse for making these objects as testable. I will also discuss that why it is hard and difficult to test ASP.NET Web Forms.
Description:
Starting from Classic ASP to ASP.NET MVC, ASP.NET Intrinsic objects is extensively used in all form of web application. They provide information about Request, Response, Server, Application and so on. But ASP.NET MVC uses these intrinsic objects in some abstract manner. The reason for this abstraction is to make your application testable. So let see the abstraction.
As we know that ASP.NET MVC uses the same runtime engine as ASP.NET Web Form uses, therefore the first receiver of the request after IIS and aspnet_filter.dll is aspnet_isapi.dll. This will start the application domain. With the application domain up and running, ASP.NET does some initialization and after some initialization it will call Application_Start if it is defined. Then the normal HTTP pipeline event handlers will be executed including both HTTP Modules and global.asax event handlers. One of the HTTP Module is registered by ASP.NET MVC is UrlRoutingModule. The purpose of this module is to match a route defined in global.asax. Every matched route must have IRouteHandler. In default case this is MvcRouteHandler which is responsible for determining the HTTP Handler which returns MvcHandler (which is derived from IHttpHandler). In simple words, Route has MvcRouteHandler which returns MvcHandler which is the IHttpHandler of current request. In between HTTP pipeline events the handler of ASP.NET MVC, MvcHandler.ProcessRequest will be executed and shown as given below,
void IHttpHandler.ProcessRequest(HttpContext context) { this.ProcessRequest(context); } protected virtual void ProcessRequest(HttpContext context) { // HttpContextWrapper inherits from HttpContextBase HttpContextBase ctxBase = new HttpContextWrapper(context); this.ProcessRequest(ctxBase); } protected internal virtual void ProcessRequest(HttpContextBase ctxBase) { . . . }
HttpContextBase is the base class. HttpContextWrapper inherits from HttpContextBase, which is the parent class that include information about a single HTTP request. This is what ASP.NET MVC team did, just wrap old instrinsic HttpContext into HttpContextWrapper object and provide opportunity for other framework to provide their own implementation of HttpContextBase. For example
public class MockHttpContext : HttpContextBase { . . . }
As you can see, it is very easy to create your own HttpContext. That's what did the third party mock frameworks like TypeMock, Moq, RhinoMocks, or NMock2 to provide their own implementation of ASP.NET instrinsic objects classes.
The key point to note here is the types of ASP.NET instrinsic objects. In ASP.NET Web Form and ASP.NET MVC. For example in ASP.NET Web Form the type of Request object is HttpRequest (which is sealed) and in ASP.NET MVC the type of Request object is HttpRequestBase. This is one of the reason that makes test in ASP.NET WebForm is difficult. because their is no base class and the HttpRequest class is sealed, therefore it cannot act as a base class to others. On the other side ASP.NET MVC always uses a base class to give a chance to third parties and unit test frameworks to create thier own implementation ASP.NET instrinsic object.
Therefore we can say that in ASP.NET MVC, instrinsic objects are of type base classes (for example HttpContextBase) .Actually these base classes had it's own implementation of same interface as the intrinsic objects it abstracts. It includes only virtual members which simply throws an exception. ASP.NET MVC also provides the corresponding wrapper classes (for example, HttpRequestWrapper) which provides a concrete implementation of the base classes in the form of ASP.NET intrinsic object. Other wrapper classes may be defined by third parties in the form of a mock object for testing purpose.
So we can say that a Request object in ASP.NET MVC may be HttpRequestWrapper or may be MockRequestWrapper(assuming that MockRequestWrapper class is used for testing purpose). Here is list of ASP.NET instrinsic and their implementation in ASP.NET MVC in the form of base and wrapper classes.
Base Class
Wrapper Class
ASP.NET Intrinsic Object
Description
HttpApplicationStateBase
HttpApplicationStateWrapper
Application
HttpApplicationStateBase abstracts the intrinsic Application object
HttpBrowserCapabilitiesBase
HttpBrowserCapabilitiesWrapper
HttpBrowserCapabilities
HttpBrowserCapabilitiesBase abstracts the HttpBrowserCapabilities class
HttpCachePolicyBase
HttpCachePolicyWrapper
HttpCachePolicy
HttpCachePolicyBase abstracts the HttpCachePolicy class
HttpContextBase
HttpContextWrapper
HttpContext
HttpContextBase abstracts the intrinsic HttpContext object
HttpFileCollectionBase
HttpFileCollectionWrapper
HttpFileCollection
HttpFileCollectionBase abstracts the HttpFileCollection class
HttpPostedFileBase
HttpPostedFileWrapper
HttpPostedFile
HttpPostedFileBase abstracts the HttpPostedFile class
HttpRequestBase
HttpRequestWrapper
Request
HttpRequestBase abstracts the intrinsic Request object
HttpResponseBase
HttpResponseWrapper
Response
HttpResponseBase abstracts the intrinsic Response object
HttpServerUtilityBase
HttpServerUtilityWrapper
Server
HttpServerUtilityBase abstracts the intrinsic Server object
HttpSessionStateBase
HttpSessionStateWrapper
Session
HttpSessionStateBase abstracts the intrinsic Session object
HttpStaticObjectsCollectionBase
HttpStaticObjectsCollectionWrapper
HttpStaticObjectsCollection
HttpStaticObjectsCollectionBase abstracts the HttpStaticObjectsCollection class
Summary:
ASP.NET MVC provides a set of abstract classes for ASP.NET instrinsic objects in the form of base classes, allowing someone to create their own implementation. In addition, ASP.NET MVC also provide set of concrete classes in the form of wrapper classes. This design really makes application easier to test and even application may replace concrete implementation with thier own implementation, which makes ASP.NET MVC very flexable.