2016-11-18 20 views
7

我正在寫一個簡單的測試用例,測試我的控制器在調用我的服務之前調用緩存。我正在使用xUnit和Moq來完成任務。正確的方式測試ASP.NET核心IMemoryCache

我正面臨一個問題,因爲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); 
} 

我不能的事實,我偷看進入的MemoryCache實現細節和它睡可以在任何時候改變。

以供參考,這是SUT代碼:

public async Task<MyViewModel> Search(SearchRequestViewModel request) 
{ 
    return await cache.GetOrCreateAsync(request.Serialized(), (e) => search.FindAsync(request)); 
} 

,你會推薦不同的測試任何?

+2

你不應該測試'IMemoryCache',因爲它是一個庫的一部分。圖書館的作者應該做測試。 –

回答

14

說實話,我會建議不要測試這種互動。

我會對這個測試案例有所不同:你真正關心的是,一旦你的控制器從你的ISearchService中檢索到數據,它不應該再次請求數據,並且應該返回前一次調用的結果。

在幕後使用IMemoryCache這一事實只是一個實現細節。我甚至不打算爲它設置一個測試雙精度,我只是使用Microsoft.Extensions.Caching.Memory.MemoryCache對象的一個​​實例。

我的新測試將是這個樣子:

[Theory] 
public async Task GivenResultAlreadyRetrieved_ShouldNotCallServiceAgain() 
{ 
    // Arrange 
    var expected = new MyViewModel(); 
    object actualOut; 

    var cache = new MemoryCache(new MemoryCacheOptions()); 
    var searchService = new Mock<ISearchService>(); 

    var input = new SearchRequestViewModel(); 

    searchService 
     .SetupSequence(s => s.FindAsync(It.IsAny<SearchRequestViewModel>())) 
     .Returns(Task.FromResult(expected)) 
     .Returns(Task.FromResult(new MyViewModel())); 

    var sut = new MyController(cache, searchService.Object); 

    // Act 
    var resultFromFirstCall = await sut.Search(input); 
    var resultFromSecondCall = await sut.Search(input); 

    // Assert 
    Assert.Same(expected, resultFromFirstCall); 
    Assert.Same(expected, resultFromSecondCall); 
} 
+0

我更喜歡你的方法。謝謝! –