如何使用 It.IsAny AddItemFactory 函数模拟 IAppCache 的 GetOrAddAsync 方法

How to mock IAppCache's GetOrAddAsync method with It.IsAny AddItemFactory function

我正在测试的方法中有这段代码:

var devices = await _cache.GetOrAddAsync(_cacheKey, AddItemFactory, DateTimeOffset.Now.AddMinutes(Configuration.DeviceInMinutes));`

其中 _cacheIAppCache 并且在测试中被 new Mock<IAppCache>(); 模拟

AddItemFactory 具有以下签名:

private async Task<IDictionary<int, Device>> AddItemFactory()

在我的测试中我写了:

        _appCache.Setup(x => x.GetOrAddAsync(
            It.IsAny<string>(),
            It.IsAny<Func<Task<IDictionary<int, Device>>>>(),
            It.IsAny<DateTimeOffset>())
        ).ReturnsAsync(fakeDictionary);

评估 .Setup 时,我的测试崩溃并出现以下错误:

System.NotSupportedException : Invalid setup on an extension method: x => x.GetOrAddAsync<IDictionary<int, Device>>(It.IsAny<string>(), It.IsAny<Func<Task<IDictionary<int, Device>>>>(), It.IsAny<DateTimeOffset>())

我认为它被正确地嘲笑了,因为 Visual Studio intellisense 没有抱怨并且签名是错误的,但我不明白发生了什么。

GetOrAddAsync 方法重载是一个扩展方法;不能模拟扩展方法。

GetOrAddAsync<T>(
      this IAppCache cache,
      string key,
      Func<Task<T>> addItemFactory,
      DateTimeOffset expires)

您需要在IAppCache接口上模拟以下方法:

Task<T> GetOrAddAsync<T>(string key, Func<ICacheEntry, Task<T>> addItemFactory);

如果您想使用 Moq 来执行此操作,库 LazyCache.Testing.Moq(免责声明 - 我是作者)通过以下设置实现此操作:

cachingServiceMock.Setup(m => m.GetOrAddAsync(
    It.IsAny<string>(),
    It.IsAny<Func<ICacheEntry, Task<T>>>()))    
    .Returns(Task.FromResult(cacheEntryValue));

其中 cacheEntryValue 是调用应该 return 的任务结果值。

如果您不需要使用 Moq,假设您使用的是 GetOrAdd* 方法,您应该能够使用 LazyCache 库提供的内置伪造 (MockCachingService) doco.