简体   繁体   English

测试ASP.NET Core IMemoryCache的正确方法

[英]Proper way of testing ASP.NET Core IMemoryCache

I'm writing a simple test case that tests that my controller calls the cache before calling my service. 我正在编写一个简单的测试用例,测试我的控制器在调用我的服务之前调用缓存。 I'm using xUnit and Moq for the task. 我正在使用xUnit和Moq来完成任务。

I'm facing an issue because GetOrCreateAsync<T> is an extension method, and those can't be mocked by the framework. 我遇到了一个问题,因为GetOrCreateAsync<T>是一个扩展方法,并且框架无法模拟这些方法。 I relied on internal details to figure out I can mock TryGetValue instead and get away with my test (see https://github.com/aspnet/Caching/blob/c432e5827e4505c05ac7ad8ef1e3bc6bf784520b/src/Microsoft.Extensions.Caching.Abstractions/MemoryCacheExtensions.cs#L116 ) 我依靠内部细节来弄清楚我可以模拟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);
}

I can't sleep with the fact that I'm peeking into the MemoryCache implementation details and it can change at any point. 我无法入睡,因为我正在窥视MemoryCache实现细节,它可以在任何时候改变。

For reference, this is the SUT code: 作为参考,这是SUT代码:

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

Would you recommend testing any differently? 您会建议以不同方式进行测试吗

To be honest I would recommend not to test this interaction at all. 说实话,我建议不要测试这种互动。

I would approach this test case a bit differently: what you really care about is that once your controller retrieved data from your ISearchService it shouldn't request the data again and should return the result from the previous call. 我会稍微改变一下这个测试用例:你真正关心的是,一旦你的控制器从你的ISearchService检索数据,它就不应该再次请求数据,而应该返回前一次调用的结果。

The fact that an IMemoryCache is used behind the scenes is just an implementation detail. 在幕后使用IMemoryCache的事实只是一个实现细节。 I wouldn't even bother setting up a test double for it, I would just use an instance of the Microsoft.Extensions.Caching.Memory.MemoryCache object. 我甚至不打算为它设置一个测试双,我只使用一个Microsoft.Extensions.Caching.Memory.MemoryCache对象的实例。

My new test would look something like this: 我的新测试看起来像这样:

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

    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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 XUnit如何模拟IMemoryCache ASP.NET Core - XUnit how to mock IMemoryCache ASP.NET Core ASP.NET 内核将带 IMemoryCache 的内存缓存转换为 Redis - ASP.NET Core Converting In-Memory Cache with IMemoryCache to Redis 如果*不*注入依赖项,是否可以在 ASP.NET Core 中使用 IMemoryCache? - Possible to use IMemoryCache in ASP.NET Core if it is *not* dependency injected? 为什么在ASP.Net Core中获取IMemoryCache的多个实例? - Why getting multiple instances of IMemoryCache in ASP.Net Core? 在 ASP.net 核心应用程序中使用 IMemoryCache 和 Unity DI Container - Use IMemoryCache with Unity DI Container in ASP.net core application ASP.NET 内核 - 更新缓存列表的 1 个元素<element>在 IMemoryCache 中使用 EF Core</element> - ASP.NET Core - Update 1 Element of a cached List<Element> in IMemoryCache using EF Core 如何从 ASP.NET 核心中的 IMemoryCache 中删除所有对象(重置) - How to remove all objects (reset ) from IMemoryCache in ASP.NET core 在 asp.net 内核中正确处理资源 - Proper handling of resources in asp.net core 在ASP.NET Core中正确实现NRT - Proper implementation NRT in ASP.NET Core ASP.Net核心集成测试 - ASP.Net Core Integration Testing
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM