我正试图IMemoryCache用Moq 嘲笑.我收到这个错误:
Moq.dll中出现"System.NotSupportedException"类型的异常,但未在用户代码中处理
附加信息:表达式引用不属于模拟对象的方法:x => x.Get <String>(It.IsAny <String>())
我的嘲弄代码:
namespace Iag.Services.SupplierApiTests.Mocks
{
public static class MockMemoryCacheService
{
public static IMemoryCache GetMemoryCache()
{
Mock<IMemoryCache> mockMemoryCache = new Mock<IMemoryCache>();
mockMemoryCache.Setup(x => x.Get<string>(It.IsAny<string>())).Returns("");<---------- **ERROR**
return mockMemoryCache.Object;
}
}
}
Run Code Online (Sandbox Code Playgroud)
为什么我会收到这个错误?
这是测试中的代码:
var cachedResponse = _memoryCache.Get<String>(url);
Run Code Online (Sandbox Code Playgroud)
哪种_memoryCache类型IMemoryCache
我如何模拟_memoryCache.Get<String>(url)上面的内容并让它返回null?
编辑:我怎么做同样的事情,但为 _memoryCache.Set<String>(url, response);?我不介意它返回什么,我只需要将方法添加到mock中,这样它就不会在调用时抛出.
我试着回答这个问题的答案:
mockMemoryCache
.Setup(m => m.CreateEntry(It.IsAny<object>())).Returns(null as ICacheEntry);
Run Code Online (Sandbox Code Playgroud)
因为在memoryCache扩展中它显示它CreateEntry在内部使用Set.但是"对象引用没有设置为对象的实例"是错误的.
我正在编写一个简单的测试用例,测试我的控制器在调用我的服务之前调用缓存.我正在使用xUnit和Moq来完成任务.
我面临一个问题,因为它GetOrCreateAsync<T>是一种扩展方法,并且不能被框架嘲笑.我依靠内部细节来弄清楚我可以嘲笑TryGetValue并躲开我的测试(参见https://github.com/aspnet/Caching/blob/c432e5827e4505c05ac7ad8ef1e3bc6bf784520b/src/Microsoft.Extensions.Caching.Abstractions/MemoryCacheExtensions.cs# L116)
[Theory, AutoDataMoq]
public async Task GivenPopulatedCacheDoesntCallService(
Mock<IMemoryCache> cache,
SearchRequestViewModel input,
MyViewModel expected)
{
object expectedOut = expected;
cache
.Setup(s => s.TryGetValue(input.Serialized(), out expectedOut))
.Returns(true);
var sut = new MyController(cache.Object, Mock.Of<ISearchService>());
var actual = await sut.Search(input);
Assert.Same(expected, actual);
}
Run Code Online (Sandbox Code Playgroud)
我无法入睡,因为我正在窥视MemoryCache实现细节,它可以在任何时候改变.
作为参考,这是SUT代码:
public async Task<MyViewModel> Search(SearchRequestViewModel request)
{
return await cache.GetOrCreateAsync(request.Serialized(), (e) => search.FindAsync(request));
}
Run Code Online (Sandbox Code Playgroud)
您会建议以不同方式进行测试吗
我知道 IMemoryCache.Set 是一个扩展方法,所以它不能被嘲笑。人们已经为这种情况提供了解决方法,例如 NKosi在这里提供的解决方法。我想知道如何为我的数据访问层实现这一点,其中我的 MemoryCache 返回一个值,当找不到它时,它从数据库中获取数据,将其设置为 MemoryCache 并返回所需的值。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是我的单元测试 - 当然它不起作用,因为我无法模拟 IMemoryCache
[Fact]
public void GetMessage_ReturnsString()
{
//Arrange …Run Code Online (Sandbox Code Playgroud)