The other day I was writing some unit tests for testing my MVC application’s forms authentication classes.  I needed to Mock the System.Web.HttpContext object.  There are a couple of ways to do this depending on the version of Visual Studio you are using (i.e. Professional, Premium/Ultimate/Enterprise) and how deep you wish to provide some default data.   One takes a little more leg work and requires some manual data setting, but gives you greater control.  While the other requires less coding for simple basic use.

Microsoft Fakes Framework

Let’s start with the option that requires a little more effort first, namely, Microsoft Fakes.  Microsoft Fakes allows you to test various pieces (or, units) of your application using stubs or shims.  A stub allows you to provide alternate code for a method or for implementing an interface.  Shims, however, rewrite your code at run-time (and, therefore, typically have a performance hit on unit tests) and are used primarily for private methods, static methods and sealed types.

Most mocking libraries do not provide a mechanism for mocking private methods, static methods or sealed types.  Therefore, for these objects where shims are required, Microsoft Fakes must be used.  (There are a few mocking libraries that do provide mocking capabilities for these types of objects, but they all have their own pros and cons, including Microsoft Fakes.)  One of the major cons for Microsoft Fakes is that its use is limited to Visual Studio Premium/Ultimate/Enterprise editions because it relies on the analysis tools and these tools aren’t available in the Visual Studio Professional or Community editions.

One more gotcha, Microsoft Fakes Framework sometimes doesn’t play nicely when additional mocking libraries are used in a unit test.  You may get some weird, unexpected results, if not an exception.  As usual with unit tests, make them as simple as possible.

Because shimmed code needs to be rewritten at run-time, shims are created in what’s known as a context.  This context operates as a boundary for all calls to the shimmed object.  In a fashion that is similar to stubbing, any call to the shimmed object is “hijacked” and rerouted to the object’s shim, returning a predetermined result.

Let’s say I wanted to shim the property System.DateTime.Now, here’s what the sample code would look like:

using System;
using System.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.QualityTools.Testing.Fakes;

namespace MyNamespace
{
    [TestClass]
    public MyClass
    {
        [TestMethod]
        public void MyTestMethod()
        {
            using (ShimsContext.Create())
            {
                // Arrange
                ShimDateTime.NowGet = () =>
                    {
                        return new DateTime(2015, 1, 1, 8, 0, 0);
                    };

                // Act
                var date = DateTime.Now;

                // Assert
                Assert.AreEqual(DateTime(2015, 1, 1, 8, 0, 0), date, "Dates are not equal.");
            }
        }
    }
}

Notice, again, that I’m using a disposable shim context to intercept all calls to System.DateTime.Now.  I then place a delegate method on the Get accessor of the System.DateTime.Now (ShimDateTime.NowGet) that returns a date I’ve specified.  Now, where ever System.DateTime.Now is called from anywhere in my code inside of the context, January 1, 2015, 8:00 AM is returned.  I have now created an expectation around which I can build a unit test.

I can do the same thing for the System.Web.HttpContext.  Before I do, however, I need Visual Studio to build a fakes assembly based on the System.Web assembly.  Because Visual Studio will initially hiccup when you attempt to do this, check out a previous post on why and how to overcome the fussiness of Visual Studio in order to create the System.Web.fakes assembly.  In the end, you’ll need your System.Web metadata file to look like the following:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="System.Web" Version="4.0.0.0"/>
  <StubGeneration>
    <Clear />
    <Add Interfaces="true"/>
  </StubGeneration>
  <ShimGeneration>
    <Clear />
    <Add Namespace="System.Web"/>
  </ShimGeneration>
</Fakes>

Now, once you’ve modified your metadata file and have added your System.Web.fakes assembly, you can use the generated fakes in your unit tests like such:

using System;
using System.Fakes;
using System.Web;
using System.Web.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.QualityTools.Testing.Fakes;

namespace MyNamespace
{
    [TestClass]
    public MyClass
    {
        [TestMethod]
        public void MyTestMethod()
        {
            using (ShimsContext.Create())
            {
                // Arrange
                ShimHttpContext.AllInstances.RequestGet = () =>
                    {
                        return new ShimHttpRequest() {
                            UrlGet = () => 
                                {
                                    return "http://contoso.com";
                                };
                        };
                    };

                ShimHttpContext.CurrentGet = () =>
                    {
                        return new ShimHttpContext();
                    };

                // Act

                // Assert

            }
        }
    }
}

The above code shims and mocks the HttpContext object and, for all instances, returns “http://contoso.com” for any code that attempts to access the HttpContext.Request.Url property.  This may work in some circumstances within your code.  However, note that typically the HttpRequest object requires many properties to hydrated in order to work properly.  Typically, there are only a few properties that are set, which, in turn, set private properties that all of HttpRequest‘s properties read from.  So, where in some cases one property is set, your code may still fail as other required properties have not been set.  This is the problem many times with attempting to shim HttpContext.  Additionally, trying to set cookies in the HttpResponse or getting properties like the UrlReferrer, requires a lot of setup for the shim.  Luckily, there’s a much easier alternative to shimming the HttpContext.  And, granted, because HttpContext is a public class, you would be better off stubbing this class instead of shimming it.  But, hey, what’s another example?  Right?

Moq

An alternative mocking framework that I use extensively for stubbing is Moq.  With Moq, stubbing System.Web.HttpContext is quite easy.  Take a look at the below code:

using System;
using System.Web;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace MyNamespace
{
    [TestClass]
    public MyClass
    {
        [TestMethod]
        public void MyTestMethod()
        {
            // Arrange
            var context = new Mock<HttpContextBase>();
            var request = new Mock<HttpRequestBase>();
            var response = new Mock<HttpResponseBase>();

            request.Setup(r => r.UrlReferrer).Returns(new Uri("http://tempuri.org/?ReturnUrl=%2f"));
            response.Setup(r => r.Cookies).Returns(new HttpCookieCollection());
            context.Setup(c => c.Request).Returns(request.Object);
            context.Setup(c => c.Response).Returns(response.Object);

            // Act

            // Assert

        }
    }
}

With the above code, you’ll see that I’m creating three objects – HttpContextHttpRequest, and HttpResponse – in order to be test some functionality of my code.  The nice thing about stubbing, as compared to shimming, is that stubs will instantiate objects using their defined constructors.  By using shims, remember, you are rewriting code at run-time – this includes the constructors.  So, like I said above, not all properties get set as expected and will often throw NullReferenceException‘s.

Moq nicely creates these three stubs for us and hydrates the minimum properties required to use the stubs.  Then, I perform a series of “setup’s” where I setup default return values for specific properties.  Based on the above code, any place in my unit test that makes a reference to Request.UrlReferrer returns “http://tempuri.org/?ReturnUrl=%2f”.  Additionally, I instantiate an HttpCookieCollection for adding cookies to my response.

As you can see this is much easier than attempting to shim.  But, when do I use which?  Well, I’m glad you asked.

Stubs vs. Shims

Microsoft has some good points on the subject and, if you ever wish to get certified in some of their verticals, you’ll need to know the difference.  Here’s a breakdown in table format:

Stub Shim
Performance Stubs do not have any additional performance overhead and are as fast as virtual methods can go. Shims run slower because they rewrite your code at run-time.
Static methods, sealed types Stubs are used to implemented interfaces and therefore cannot be used. Shims must be used.
Internal types Both stubs and shims can be used with internal types that are made accessible by using the assembly attribute InternalsVisibleToAttribute.
Private methods Cannot be used because stubs only replace visible methods. Can be used as long as all types used in the method are visible.
Interfaces and abstract methods Stubs provide implementations of interfaces and abstract methods that can be used in testing. Shims can’t instrument interfaces and abstract methods because they don’t have method bodies.

As Microsoft states, stubs should typically be used to isolate from dependencies used in your code.  Shims are to be used when accessing 3rd-party components that do not provide a testable API.

Good rule of thumb, make stubs for public classes exposed by interfaces.  Use shims for sealed classes, static methods, and private methods.

In order to make sense of all of this, let’s look at another example.  Dave Ferguson wrote a blog article about abstracting the ASP.NET FormAuthentication library to an interface so that an MVC action could be unit tested while intercepting any call to the FormsAuthentication library methods.  While this maybe required for users using VisualStudio Professional or Community Editions, fakes actually make this a little easier.

Here’s the fakes version of an actual unit test for signing out a user. (Notice, no interface is required.)

using System;
using System.Web;
using System.Web.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.QualityTools.Testing.Fakes;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;

namespace MyNamespace
{
    [TestClass]
    public MyClass
    {
        [TestMethod]
        public void Logout__LogsOutUserAndRedirectToLogin()
        {
            using (ShimsContext.Create())
            {
                // Arrange
                System.Web.Security.Fakes.ShimFormsAuthentication.SignOut = () =>
                    {
                        return;
                    };

                var context = new Mock<HttpContextBase>();
                var request = new Mock<HttpRequestBase>();

                request.Setup(r => r.IsAuthenticated).Returns(true);
                context.Setup(c => c.Request).Returns(request.Object);

                c.AuthenticationController con = new c.AuthenticationController();
                con.ControllerContext = new ControllerContext(context.Object, new RouteData(), con);

                // Act
                var result = con.Logout();

                // Assert
                Assert.IsTrue(result.GetType() == typeof(RedirectToRouteResult), "Returned result was not of type 'RedirectToRouteResult'.");
                Assert.AreEqual("Login", ((RedirectToRouteResult)result).RouteValues["action"], string.Format("Action expected: 'Login' actual: '{0}'", ((RedirectToRouteResult)result).RouteValues["action"]));
                Assert.AreEqual("Authentication", ((RedirectToRouteResult)result).RouteValues["controller"], string.Format("Action expected: 'Authentication' actual: '{0}'", ((RedirectToRouteResult)result).RouteValues["controller"]));
            }
        }
    }
}

And, one more that adds a cookie for good measure…

using System;
using System.Web;
using System.Web.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.QualityTools.Testing.Fakes;
using f = MyNamespace.Common.Infrastructure.Security.Fakes;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;

namespace MyNamespace
{
    [TestClass]
    public MyClass
    {
        [TestMethod]
        public void Login_CorrectCredentialsAndReturnUrl_RedirectToReturnUrl()
        {
            using (ShimsContext.Create())
            {
                // Arrange
                f.ShimMembership.AuthenticateStringStringBooleanVerificationStatusOut = (string u, string pa, bool pe, out Common.Infrastructure.Security.VerificationStatus status) =>
                {
                    status = Common.Infrastructure.Security.VerificationStatus.Authenticated;
                    return new HttpCookie("test");
                };

                var context = new Mock<HttpContextBase>();
                var request = new Mock<HttpRequestBase>();
                var response = new Mock<HttpResponseBase>();

                request.Setup(r => r.UrlReferrer).Returns(new Uri("http://tempuri.org/?ReturnUrl=%2f"));
                response.Setup(r => r.Cookies).Returns(new HttpCookieCollection());
                context.Setup(c => c.Request).Returns(request.Object);
                context.Setup(c => c.Response).Returns(response.Object);

                c.AuthenticationController con = new c.AuthenticationController();
                con.ControllerContext = new ControllerContext(context.Object, new RouteData(), con);

                LoginViewModel model = new LoginViewModel();

                // Act
                var result = con.Login(model);

                // Assert
                Assert.IsTrue(result.GetType() == typeof(RedirectResult), "Returned result was not of type 'RedirectResult'.");
                Assert.AreEqual("/", ((RedirectResult)result).Url, string.Format("RedirectUrl is not expected. Expected: '/'  Actual: '{0}'", ((RedirectResult)result).Url));
            }
        }
    }
}

In this case, I have a custom membership library that handles authentication and returning a forms authentication cookie which, in my MVC login action, is added to the HttpResponse.  For my unit test, I don’t want the class methods to be called so I call a shim instead that returns a new HttpCookie.  Note, as you see in the above code, when using the out keyword on a parameter in a shim, you must fully qualify the type.  Furthermore, ref‘s cannot be used in shims.

Let me know if you have questions or get stuck…I’ll be glad to help you.