You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, writing tests with the HybridCache abstraction is a little clunky. Essentially, you have to mock out the more complex GetOrCreateAsync() method. While this isn't hard to write a simple set of extensions to do so (which I'll include below), having something akin to what TimeProvider has, Microsoft.Extensions.TimeProvider.Testing that provides a FakeTimeProvider, would be most welcome.
I don't foresee a hypothetical FakeHybridCache having to do much, as the only contracted method is GetOrCreateAsync(). There's no need to add support for building out fake memory / distributed caches to control cache hits/misses. Rather, having a simple way to control what gets returned when called with a specific key (or tags perhaps too) would be all that's required.
Here's a little something I whipped up, using NSubstitute, to support both "I want to mock some fake return data from my cache" and "I want to assert my cache was called / used." Obviously this is quick and dirty and I just pass null or "any argument allowed" for the majority of things, but you can see where something like this would be beneficial in an official capacity. (Not strictly for NSubstitute, mind; methods that simply let us set up fake data or test that calls happened (a simple counter) would be all that's needed.)
usingMicrosoft.Extensions.Caching.Hybrid;usingNSubstitute;usingNSubstitute.Core;namespaceExample;/// <summary>/// Extension methods to make testing <see cref="HybridCache" /> easier in NSubstitute/// </summary>publicstaticclassNSubstituteHybridCacheExtensions{publicstaticConfiguredCallSetupGetOrCreateAsync(thisHybridCachemockCache,stringkey,stringexpectedValue){returnmockCache.GetOrCreateAsync(key,Arg.Any<object>(),Arg.Any<Func<object,CancellationToken,ValueTask<string>>>(),Arg.Any<HybridCacheEntryOptions?>(),Arg.Any<IEnumerable<string>?>(),Arg.Any<CancellationToken>()).Returns(expectedValue);}publicstaticasyncTaskAssertGetOrCreateAsyncCalledAsync(thisHybridCachemockCache,stringkey,intrequiredNumberOfCalls){awaitmockCache.Received(requiredNumberOfCalls).GetOrCreateAsync(key,Arg.Any<object>(),Arg.Any<Func<object,CancellationToken,ValueTask<string>>>(),null,null,Arg.Any<CancellationToken>());}}
And my unit test code has something like this:
usingFluentAssertions;usingMicrosoft.Extensions.Caching.Hybrid;usingNSubstitute;usingXUnit;namespaceUnitTesting;publicclassMyTests{privatereadonlyHybridCache_mockCache=Substitute.For<HybridCache>();[Fact]publicasyncTaskSomething(){// Mocking a return value_mockCache.SetupGetOrCreateAsync("some-key",expectedValue);// Asserting the cache was calledawait_mockCache.AssertGetOrCreateAsyncCalledAsync("some-key",1);}}
There's tons to improve here, but here's a super basic not-fully-implemented FakeHybridCache that could be a jumping off point.
usingMicrosoft.Extensions.Caching.Hybrid;namespaceMicrosoft.Extensions.Caching.Hybrid.Testing;publicclassFakeHybridCache:HybridCache{// Not sure if this should be static, nor do I know what to do about Tags// Could make public since it's a fake cache anyway, and that could be useful for testing purposesprivatereadonlyDictionary<string,object?>_cache=new();publicoverrideasyncValueTask<T>GetOrCreateAsync<TState,T>(stringkey,TStatestate,Func<TState,CancellationToken,ValueTask<T>>factory,HybridCacheEntryOptions?options=null,IEnumerable<string>?tags=null,CancellationTokencancellationToken=default){boolcached=_cache.TryGetValue(key,outobject?value);if(cached)return(T?)value!;_cache.Add(key,awaitfactory(state,cancellationToken));return(T?)_cache[key]!;}publicoverrideValueTaskSetAsync<T>(stringkey,Tvalue,HybridCacheEntryOptions?options=null,IEnumerable<string>?tags=null,CancellationTokencancellationToken=default){_cache[key]=value;returnValueTask.CompletedTask;}publicoverrideValueTaskRemoveAsync(stringkey,CancellationTokencancellationToken=default){_cache.Remove(key);returnValueTask.CompletedTask;}publicoverrideValueTaskRemoveByTagAsync(stringtag,CancellationTokencancellationToken=default){thrownewNotImplementedException();}}
The text was updated successfully, but these errors were encountered:
Currently, writing tests with the
HybridCache
abstraction is a little clunky. Essentially, you have to mock out the more complexGetOrCreateAsync()
method. While this isn't hard to write a simple set of extensions to do so (which I'll include below), having something akin to whatTimeProvider
has, Microsoft.Extensions.TimeProvider.Testing that provides aFakeTimeProvider
, would be most welcome.I don't foresee a hypothetical
FakeHybridCache
having to do much, as the only contracted method isGetOrCreateAsync()
. There's no need to add support for building out fake memory / distributed caches to control cache hits/misses. Rather, having a simple way to control what gets returned when called with a specific key (or tags perhaps too) would be all that's required.Here's a little something I whipped up, using
NSubstitute
, to support both "I want to mock some fake return data from my cache" and "I want to assert my cache was called / used." Obviously this is quick and dirty and I just passnull
or "any argument allowed" for the majority of things, but you can see where something like this would be beneficial in an official capacity. (Not strictly forNSubstitute
, mind; methods that simply let us set up fake data or test that calls happened (a simple counter) would be all that's needed.)And my unit test code has something like this:
There's tons to improve here, but here's a super basic not-fully-implemented
FakeHybridCache
that could be a jumping off point.The text was updated successfully, but these errors were encountered: