Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing CacheManager

I have this CacheManager class which keeps a static dictionary with all sorts of cached data. However, with this dictionary being static it gets filled up with data from the other unit tests. This keeps me from unit testing whether or not the CacheManager is empty on init, and breaks with the principles of unit testing.

Any ideas how to create a proper unit test for this?

Code

public class CacheManager
{
   private static readonly Dictionary<ICacheKey, ListCacheItem> cacheEntries =
       new Dictionary<ICacheKey, ListCacheItem>();

   public static Dictionary<ICacheKey, ListCacheItem> CacheEntries
   {
       get
       {
           lock (cacheEntries)
           {
               return cacheEntries;
           }
       }
   }
like image 983
koenmetsu Avatar asked Nov 06 '22 11:11

koenmetsu


2 Answers

Generally, this is not a good idea from a testing perspective. By making the members of CacheManager static, you will never be able to isolate it in such a way to make it nice to unit test.

Perhaps a better solution is the Singleton Pattern. To do this, get rid of the static modifiers on CacheManager's members. Then you can have one static instance in your app that is used by everyone else. Therefore, in your unit test, you could create a new instance of the class that you can test in isolation, but still have the desired functionality.

like image 153
3 revs Avatar answered Nov 15 '22 13:11

3 revs


Short answer: you can not do it properly. Unit testing and statics do not play really well together, you will (almost) always run into problems like the one you mentioned.

Longer answer: best solution would be to refactor your code. Even if you need the singleton behavior you have several options (e.g. dependency injection). David's recommendation is of course also an option that would at least let you test your cache, but you may still have problems when you want to test the rest of the system.

If for some reason you want to stick to your current design you can still have some (not necessary nice) workarounds. Some examples:

Easiest might be to add a "cleanCache" method. In some situations it might be even useful for the rest of the system, and each of your tests could also do it as the first step (in "setup/beforeTest or similar methods").

You could also play with visibility and let your tests do cleanup that is not allowed for the rest of the code.

These hacks will probably work as long as you do not run your tests in parallel.

like image 35
Sandor Murakozi Avatar answered Nov 15 '22 12:11

Sandor Murakozi