Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking System.Web.Caching.Cache - Mock or check for null?

I'm writing some unit test and am wondering whether it's advantageous to mock the Cache and if so, how?

Currently in my tests I'm mocking out the HttpContextBase and wrapping it in a custom HttpContextFactory:

var mockedHttpContextBase = new Mock<HttpContextBase>();

IHttpContextFactory httpContextFactory = new HttpContextFactory 
{ 
     Current = mockedHttpContextBase.Object 
};

and when my code consumes an IHttpContextFactory I check if the cache is null before doing anything with it.

var cache = _httpContextFactory.Current.Cache;

Func<SomeReturnType> doSomeWork = () => _foo.someMethodIExecute(param1,param2);

return cache != null ? cache.GetOrStore("doSomeWorkCacheKey",doSomeWork, 900) 
                     : doSomeWork.Invoke();

Is it right to check for the cache being null like this each time I use it or would you mock the cache also in the test so that it's not null when running your unit tests?

like image 601
Jamie Dixon Avatar asked Apr 30 '12 10:04

Jamie Dixon


2 Answers

After a bit of searching it seems that I can use HttpRuntime.Cache instead of System.Web.Caching.Cache when writing my unit tests.

Such that:

var mockedHttpContextBase = new Mock<HttpContextBase>();
mockedHttpContextBase.Setup(m => m.Cache).Returns(HttpRuntime.Cache);

The cache should never be null (it would be an appropriate exception if it was) so I can remove the null reference checking from my code.

like image 160
Jamie Dixon Avatar answered Nov 06 '22 13:11

Jamie Dixon


If your code assumes cache can be null and performs checks before accessing it (as it does now), you need to have two unit tests for each cache access:

  • cache exists and item is stored and retrieved (checking GetOrStore call)
  • cache is null and you simply assert delegate invocation

If this is common pattern (null checking), instead of having two tests each time cache dependency is required, I suggest wrapping it into Null Object Pattern and have it tested once and later simply use NOP as a dependency that can be mocked.

Edit: cache "mocking" example

var cache = new Cache();
// Add takes more parameters; fill whatever is necessary to make it work
cache.Add("doSomeWorkCacheKey", doSomeWork, ...);
var mockedHttpContextBase = new Mock<HttpContextBase>();
// tell your mock to return pre-configured cache
mockedHttpContextBase.Setup(m => m.Cache).Returns(cache);

IHttpContextFactory httpContextFactory = new HttpContextFactory 
{ 
    Current = mockedHttpContextBase.Object 
};
like image 24
k.m Avatar answered Nov 06 '22 12:11

k.m