views:

456

answers:

3

How would I mock the caching object on the ControllerContext object for my unit tests? I have tried creating a wrapper class like the following (since the cache object is a sealed class) with no luck.

var mockControllerContext = new Mock<ControllerContext>(); 
var mockhttpContext = new Mock<HttpContextBase>();            

mockhttpContext.SetupGet(o => o.Cache).Returns(new CacheWrapper(mockControllerContext.Object.HttpContext.Cache));

mockControllerContext.SetupGet(o => o.HttpContext).Returns(mockhttpContext.Object);
this.tennisMatchupController.ControllerContext = mockControllerContext.Object;
+7  A: 

EDIT: I found an easier way to do this, at least when you are testing with an empty cache. Use HttpRunTime.Cache as the return value for your expectation on the Cache property of the HttpContext. For more advanced scenarios, using a wrapper and mocking may still be a better way to handle it -- for example, if you need to test exceptions from the cache.

var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Expect( h => h.Cache ).Return( HttpRunTime.Cache ).Repeat.Any()

Original:

The wrapper class is the way to go, but I think that you are applying it in the wrong place. I would give my controller a CacheWrapper property, then create a constructor that allows me to pass in a CacheWrapper instance to which this property can be set. By default the controller creates a CacheWrapper using HttpContext.Current.Cache. In your test code, construct a mock CacheWrapper to pass into the controller's constructor. This way you don't need to create a mock Cache object at all -- which is hard because it's a sealed class.

Alternatively, you could just instantiate an instance of the Cache class and return it, since there is a public constructor for it. Using the mock has the advantage that you can verify that the Cache is being used via expectations, however, so I'd probably go with the wrapper.

public class CacheWrapper
{
  private Cache Cache { get; set; }

  public CacheWrapper()
  {
     this.Cache = HttpContext.Current.Cache;
  }

  public virtual Object Add( string key,
                             Object value,
                             CacheDependency dependencies,
                             DateTime absoluteExpiration,
                             TimeSpan slidingExpiration,
                             CacheItemPriority priority,
                             CacheItemRemovedCallback onRemoveCallback )
  {
     this.Cache.Add( key,
                     value,
                     dependencies,
                     absoluteExpiration,
                     slidingExpiration,
                     priority,
                     onRemoveCallback );
  }

  ...wrap other methods...
}


public class BaseController : Controller
{
    private CacheWrapper { get; set; }

    public BaseController() : this(null) { }

    public BaseController( CacheWrapper cache )
    {
        this.CacheWrapper = cache ?? new CacheWrapper();
    }
}

[TestMethod]
public void CacheTest()
{
   var wrapper = MockRepository.GenerateMock<CacheWrapper>();

   wrapper.Expect( o => o.Add( ... ) ).Return( ... );

   var controller = new BaseController( wrapper );

   var result = controller.MyAction() as ViewResult;

   Assert.AreEqual( ... );

   wrapper.VerifyAllExpectations();
}
tvanfosson
A: 

You can try to use Typemock Isolator, it fakes sealed classes out of the box, so you won't need these wrappers.

A: 
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
Shawn Miller