Unit testing and Caching
I'm adding unit tests to the Dozing Dogs code to help me test the recent major stored procedure changes and I had a problem with my extensive caching.
What tends to happen in our code is that whenever I read something from database it gets stored into the ASP.NET Cache for a period of time or until another cache is flushed. Sometimes for 24 hours, sometimes just a minute, but usually everything is cached somehow.
So, I ran my first unit test, published here for posterity:
[TestFixtureSetUp]
public void FixtureInit()
{
dt = CategoryInfo.GetCategoryList();
}
[Test]
public void TestIDFolder()
{
foreach (DataRow dr in dt.Rows)
{
CategoryInfo.ID nID = (CategoryInfo.ID)dr["CategoryID"];
if (!CategoryInfo.IsValid(nID))
continue;
string sCat = CategoryInfo.IDtoFolder(nID);
Assert.IsTrue(sCat.Length > 0);
Assert.AreEqual(nID, CategoryInfo.FolderToID(sCat));
}
}
and like all good tests, it failed. It turns out that my caching was having issues, because in this particular code I was using HttpContext.Current.Cache, and that will be NULL when run from NUnit because there is no current web request.
I've needed to put in tests like this before, when my classes are run from a console app:
if (HttpContext.Current != null)
But that wouldn't work this time because I needed to pass data through this cache storage - one method put it in and another got the value from the cache.
So I created my own cache class wrapper, using HttpContext.Current.Cache or System.AppDomain.CurrentDomain.GetData/SetData (no idea if this would work, but it looked promising).
Everything worked ok - my caches code all worked and unit tests passed!
But being a good boy I thought that I'd step through the unit test one time, just to make sure. So I attached to NUnit-gui.exe and re-ran the tests. I was surprised to notice that System.AppDomain wasn't being used at all.
In fact, when I'd written my wrapper I had taken code from elsewhere, and that had used the equivalent (I thought) HttpRuntime.Cache instead of HttpContext.Current.Cache.
But it turns out that HttpRuntime.Cache is always available, even in console apps! Who knew?
So, I quickly threw away my new wrapper class and replaced every HttpContext.Current.Cache in my code (a LOT of them) with HttpRuntime.Cache, and removed a lot of tests for null, and now all my code is ready for NUnit.
Caveat Emptor: It may not act truly the same in console apps; but it does store/retreive values which is good enough for now. I'm not assuming that cache dependancies or expiration work the same (or at all) but since you should never depend on that, who cares?