2016-12-06 57 views
1

我想模擬一個名爲GetOrAddAsync的函數。它的定義爲:Moq和異步使用LazyCache的樂趣

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 <>中傳遞的數據填充它。

我嘲諷的這種嘗試至今如下:

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表達式鍵入「IEnumerable的」,因爲它不是一個委託類型。

我的心,願與這種語法:)

回答

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(); 
       }); 
+0

我太親近:)。謝謝你的工作! – user441521

0

而不是必須使用Moq自己模擬LazyCache API,爲什麼不使用框架提供的模擬版本呢?它只是執行你的委託被緩存的任何東西,並且從不做任何緩存。退房MockCachingService.cs