MemoryCache.Default.AddOrGetExisiting returns null although the key is in the cache

Viewed 1020

I am writing unit tests for my asp.net web API application and one of them is trying to verify that AddOrGetExisting is working correctly. According to the MSDN documentation, AddOrGetExisting returns an item if it's already saved, and if not it should write it into Cache.

The problem I am having is that if I add the key to MemoryCache object from an unit test, then call AddOrGetExisting, it will always return null and overwrite the value instead of returning the value that is already saved. I am verifying that the value is in the cache right before I call AddOrGetExisting(bool isIn evaluates to true).

Here is the code for my memory cache and the test method. Any help would be much appreciated:

public static class RequestCache
{
    public static TEntity GetFromCache<TEntity>(string key, Func<TEntity> valueFactory) where TEntity : class
    {
        ObjectCache cache = MemoryCache.Default;
        var newValue = new Lazy<TEntity>(valueFactory);
        CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) };
        bool isIn = cache.Contains(key);
        // Returns existing item or adds the new value if it doesn't exist
        var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<TEntity>;
        return (value ?? newValue).Value;
    }

}

    public string TestGetFromCache_Helper()
    {
        return "Test3and4Values";
    }

    [TestMethod]
    public void TestGetFromCache_ShouldGetItem()
    {
        ObjectCache cache = MemoryCache.Default;
        CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) };
        var cacheKey = "Test3";
        var expectedValue = "Test3Value";
        cache.AddOrGetExisting(cacheKey, expectedValue, policy);

        var result = Models.RequestCache.GetFromCache(cacheKey,
            () =>
                {
                    return TestGetFromCache_Helper();
                 });

        Assert.AreEqual(expectedValue, result);
    }
1 Answers

The issue may be that you're passing a Lazy<TEntity> as newValue within RequestCache.GetFromCache but passing a string as expectedValue in the test method.

When running the test, the cache.Contains(key) confirms that there is a value stored for that key, which is true. However it is a string instead of a Lazy<TEntity>. Apparently AddOrGetExisting decides to overwrite the value in that case.

The fix for this particular scenario may be to adjust the expectedValue assignment in your test to something like this:

var expectedValue = new Lazy<string>(TestGetFromCache_Helper);

You'd also need to pull the value from the Lazy in the test's final equality comparison, for example:

Assert.AreEqual(expectedValue.Value, result);
Related