我了解IMemoryCache.Set是一种扩展方法,因此无法模拟。人们已经针对这种情况提供了解决方法,例如NKosi here提出的解决方法。我想知道如何为我的数据访问层实现这一目标,在这里我的MemoryCache返回一个值,当找不到时,它从db获取数据,将其设置为MemoryCache并返回所需的值。
age
以下是我的单元测试-当然,它不能正常工作,因为我无法模拟IMemoryCache
public string GetMessage(int code)
{
if(myMemoryCache.Get("Key") != null)
{
var messages= myMemoryCache.Get<IEnumerable<MyModel>>("Key");
return messages.Where(x => x.Code == code).FirstOrDefault().Message;
}
using (var connection = dbFactory.CreateConnection())
{
var cacheOptions = new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromHours(1) };
const string sql = @"SELECT Code, Message FROM MyTable";
var keyPairValueData = connection.Query<KeyPairValueData>(sql);
myMemoryCache.Set("Key", keyPairValueData, cacheOptions );
return keyPairValueData.Where(x => x.Code == code).FirstOrDefault().Message;
}
}
答案 0 :(得分:1)
我要说的第一件事是为什么不使用真实内存缓存?这样可以更好地验证该行为,而无需模拟它:
snippets
如果您真的想模拟它,请参阅以下指南:
由于它是扩展方法,因此需要确保可以按原样调用它。您的情况是扩展方法将调用该模拟。由于您没有提供预期的行为,因此可能会失败。
您需要查看扩展方法的代码,检查其访问范围,然后确保您的模拟符合预期的行为。该代码在此处可用: https://github.com/aspnet/Caching/blob/master/src/Microsoft.Extensions.Caching.Abstractions/MemoryCacheExtensions.cs#L77
这是代码:
// Arrange
var memCache = new MemoryCache("name", new NameValueCollection());
//Act
var result = new DataService(dbConnectionFactoryMock.Object, memCache).GetMessage(1000);
// Assert: has been added to cache
memCache.TryGetValue("Key", out var result2);
Assert.Equal("Some message", result2);
// Assert: value is returned
Assert.Equal("Some message", result);
因此,您可以从中看到它访问public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, MemoryCacheEntryOptions options)
{
using (var entry = cache.CreateEntry(key))
{
if (options != null)
{
entry.SetOptions(options);
}
entry.Value = value;
}
return value;
}
并期望有一个对象。然后,它调用CreateEnty
并在条目上分配SetOptions
。
您可以这样模拟:
Value
执行此操作时,扩展方法将在模拟对象上调用,并将返回模拟的条目。您可以修改实现并使其做任何您想做的事情。