Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you mock the caching object in asp.net mvc?

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; 
like image 263
Korbin Avatar asked Apr 23 '09 19:04

Korbin


People also ask

How can use cache in ASP.NET MVC?

In ASP.NET MVC, there is an OutputCache filter attribute that you can apply and this is the same concept as output caching in web forms. The output cache enables you to cache the content returned by a controller action. Output caching basically allows you to store the output of a particular controller in the memory.

What are the different caching techniques available in .NET MVC?

Any (Default)- Content is cached in three locations- the Web Server, any proxy Servers and the Web Browser. Client- Content is cached on the Web Browser. Server- Content is cached on the Web Server. ServerAndClient- Content is cached on the Web Server and the Web Browser.

What is meant by caching in ASP.NET MVC?

The output cache enables you to cache the content returned by a controller action. That way, the same content does not need to be generated each and every time the same controller action is invoked. Imagine, for example, that your ASP.NET MVC application displays a list of database records in a view named Index.


2 Answers

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();
}
like image 123
tvanfosson Avatar answered Sep 27 '22 19:09

tvanfosson


I would recommend using Microsoft's new MemoryCache.Default approach. You will need to use .NET Framework 4.0 or later and include a reference to System.Runtime.Caching.

See article here --> http://msdn.microsoft.com/en-us/library/dd997357(v=vs.100).aspx

MemoryCache.Default works for both web and non-web applications. So the idea is you update your webapp to remove references to HttpContext.Current.Cache and replace them with references to MemoryCache.Default. Later, when you decide to Unit Test these same methods, the cache object is still available and won't be null. (Because it is not reliant on an HttpContext.)

This way you don't even necessarily need to mock the cache component.

like image 38
ClearCloud8 Avatar answered Sep 27 '22 19:09

ClearCloud8