Sunday, November 24, 2013

Sometimes You Gotta Fake It

In .NET 4.0 Microsoft gave us a couple of new testing tools called Shims and Fakes.  I'm not going to profess to be an expert on those topics, nor on unit testing in general.  However, I have found there to be a dearth of information available to actually utilize these new tools to do unit testing.  I've written up a nice little blurb on how to do it and I'm going to post it here for posterity.

First we must create a ShimsContext within which we can run the tests.  ShimsContext implements IDisposable so we can do this by utilizing the using statement:

// create the ShimsContext in order to use Shims later
using (ShimsContext.Create())
{
}


Within the ShimsContext we can use Shims and Fakes to specify the exact data we want to receive when we use static methods.  The first method here specifies that when DateTime.Now is called by the code under test, it should be detoured to use “11/15/2013 9:18:13”:
// create the ShimsContext in order to use Shims later
using (ShimsContext.Create())
{
// create the Shim for DateTime.Now in order to always have a specific value when DateTime.Now is called
       System.Fakes.ShimDateTime.NowGet = () => new DateTime(2013, 11, 15, 9, 18, 13);
}

The next thing we do is create a Fake for Session.  This way we can specify an exact value for each key requested from Session.  Since we can specify a value for each key, we have full control over the session and which values will be returned, including potentially returning null so we can perform negative testing.  Here we want to specify that "12345" should be returned when the code requests "UserID" from the session and "987654" when "LoginKey" is requested:


using (ShimsContext.Create())
{
<…snip…>

// create the Fake for Session
var session = new System.Web.SessionState.Fakes.ShimHttpSessionState
{
ItemGetString = key =>
{
// specify each key that will be requested by the code under test
switch (key)
{
case "UserID":
return "123456";
  case "LoginKey":
return "987654";
default:
return null;
}
}
};
}


Now that we’ve created the Session Fake we need to create the Context Fake.  In this case I want to specify that when HttpContext.Items is called by the code under test, an empty Dictionary<string, object>() is returned:

// create the ShimsContext in order to use Shims later
using (ShimsContext.Create())
{
<…snip…>

// create the Shim for HttpContext
var context = new System.Web.Fakes.ShimHttpContext
{
ItemsGet = () => new Dictionary<string, object>()
};
}


Once the Fakes are both created, we must tell the Shims to use those objects instead of the standard objects.  These two lines specify that when HttpContext.Current is referenced we should instead substitute the Fake context we created earlier and when HttpContext.Current.Session is referenced we should instead substitute the Fake session we created earlier:

// create the ShimsContext in order to use Shims later
using (ShimsContext.Create())
{
<…snip…>

// specify that when the current context is requested we return the shimmed context we created
System.Web.Fakes.ShimHttpContext.CurrentGet = () => context;
// specify that when the current session is requested we return the shimmed session we created
System.Web.Fakes.ShimHttpContext.AllInstances.SessionGet = o => session;
}


That's pretty much it for now.  Shims and Fakes are incredibly useful, especially when you need to test a method that uses values from Session to perform differently.  I'll post again soon (hopefully) on how to instantiate a static class for testing purposes.

No comments:

Post a Comment