测试ASP.NET Core IMemoryCache的正确方法 [英] Proper way of testing ASP.NET Core IMemoryCache

查看:559
本文介绍了测试ASP.NET Core IMemoryCache的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的测试用例,用于测试控制器在调用服务之前是否调用了缓存.我正在使用xUnit和Moq来完成任务.

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.

我遇到了一个问题,因为GetOrCreateAsync<T>是扩展方法,并且框架无法对其进行嘲笑.我依靠内部细节来弄清楚我可以模拟TryGetValue并逃避我的测试(请参阅

I'm facing an issue because GetOrCreateAsync<T> is an extension method, and those can't be mocked by the framework. 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)

[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实现细节的事实,并且它随时可能发生变化.

I can't sleep with the fact that I'm peeking into the MemoryCache implementation details and it can change at any point.

作为参考,这是SUT代码:

For reference, this is the SUT code:

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.

我对这个测试用例的处理方式有所不同:您真正关心的是,一旦控制器从ISearchService检索到数据,它就不会再次请求数据,而应该返回上一次调用的结果.

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.

在幕后使用IMemoryCache的事实只是实现细节.我什至不用为它设置测试倍数,我只会使用Microsoft.Extensions.Caching.Memory.MemoryCache对象的实例.

The fact that an IMemoryCache is used behind the scenes is just an implementation detail. 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.

我的新测试看起来像这样:

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

这篇关于测试ASP.NET Core IMemoryCache的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆