简体   繁体   中英

How to Flush IAppCache Between Integration Tests

I'm running integration tests with xUnit in ASP.NET, and one of which ensures that querying the data multiple times results in only 1 query to the server. If I run this test alone, then it works. If I run all the tests, then the server gets queried 0 times instead of 1 by this test. Which indicates that the result was already in the cache because of other tests.

How can I ensure the IAppCache is empty at the beginning of the test? I'm using LazyCache implementation.

My guess is that the class instance is recreated for each tests, but static data is shared; and the cache is static. I don't see any "flush" method on the cache.

As mentioned in my OP comment LazyCache afaik doesn't have a clear operation or anything native to nuke the cache. However I think there are a few options at your disposal.

  • Implement a method before/after each test to remove the cache entries, using Remove;
  • Supply a different LazyCache cache provider for the tests that doesn't persist the cache between tests
  • Dig into LazyCache, get the underlying cache provider and see if that has any methods to clear the cache entries

1 or 3 would be my picks. From a testing perspective, 1 means you need to know the internals of what you're testing. If it were me, I'm a bit lazy and would probably write the few lines to just nuke the cache.

By default LazyCache uses MemoryCache as the cache provider. MemoryCache doesn't have an explicit clear operation either but Compact looks like it can essentially clear the cache when the compact percentage is set to 1.0. To access it, you'll need to get the underlying MemoryCache object from LazyCache:

IAppCache cache = new CachingService();
var cacheProvider = cache.CacheProvider;
var memoryCache = (MemoryCache)cacheProvider.GetType().GetField("cache", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheProvider);
memoryCache.Compact(1.0);

Complete LINQPad working sample:

void Main()
{
    IAppCache cache = new CachingService();

    Console.WriteLine(cache.GetOrAdd("Foo", () => Foo.NewFoo, DateTimeOffset.Now.AddHours(1.0)));

    var cacheProvider = cache.CacheProvider;
    var memoryCache = (MemoryCache)cacheProvider.GetType().GetField("cache", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheProvider);
    memoryCache.Compact(1.0);

    Console.WriteLine(cache.Get<Foo>("Foo"));
}

public class Foo
{
    public static Foo NewFoo
    {
        get
        {
            Console.WriteLine("Factory invoked");
            return new Foo();
        }
    }

    public override string ToString()
    {
        return "I am a foo";
    }
}

This results in the following each run:

在此处输入图像描述

If I remove the compact invocation we get the following:

在此处输入图像描述

So that shows that Compact(1.0) will nuke the cache entry even with an expiry date of +1 hour.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM