使用LazyCache

时间:2016-12-06 22:33:16

标签: c# unit-testing moq

我试图模拟一个名为GetOrAddAsync的函数。它被定义为:

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

当我在实际代码中使用它时,我使用它:

DateTimeOffset cacheTimeout = new DateTimeOffset(DateTime.Now.AddHours(config.CacheHours));
Func<Task<IEnumerable<int>>> func = async () => await (from s in dbContext.Names select s.First).ToListAsync();

return await cache.GetOrAddAsync(key, func, cacheTimeout);

所以基本上如果密钥存在,它将返回其中的内容,如果不存在,它将创建一个密钥并用传入的Func&lt;&gt;返回的数据填充它。

到目前为止,我对此的嘲弄尝试如下:

cache.Setup(x => x.GetOrAddAsync(It.IsAny<string>(), It.IsAny<Func<Task<IEnumerable<int>>>>(), It.IsAny<DateTimeOffset>()))
                .ReturnsAsync(async (string key, Func<Task<IEnumerable<int>>> func, DateTimeOffset policy) =>
                    {
                        return await func.Invoke();
                    });

但是,这会返回错误:

无法将lambda表达式转换为类型&#39; IEnumerable&#39;因为它不是代表类型。

我的思绪已准备好用这种语法爆炸:)

2 个答案:

答案 0 :(得分:2)

当您拥有异步回调函数时,不会使用ReturnsAsync,更多地考虑它,因为.ReturnsAsync(foo)只是.Returns(Task.FromResult(foo))的简写。所以你要做的就是

cache.Setup(x => x.GetOrAddAsync(It.IsAny<string>(), It.IsAny<Func<Task<IEnumerable<int>>>>(), It.IsAny<DateTimeOffset>()))
                .Returns(Task.FromResult(async (string key, Func<Task<IEnumerable<int>>> func, DateTimeOffset policy) =>
                    {
                        return await func.Invoke();
                    }));

更改为使用普通Returns(,您的功能应该可以正常工作。

cache.Setup(x => x.GetOrAddAsync(It.IsAny<string>(), It.IsAny<Func<Task<IEnumerable<int>>>>(), It.IsAny<DateTimeOffset>()))
            .Returns(async (string key, Func<Task<IEnumerable<int>>> func, DateTimeOffset policy) =>
                {
                    return await func.Invoke();
                });

答案 1 :(得分:0)

为什么不使用框架提供的模拟版本,而不是自己使用Moq模拟LazyCache API?它只执行您要缓存的任何代理,并且永远不会执行任何缓存。查看MockCachingService.cs