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

查看:22
本文介绍了测试 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 是一种扩展方法,框架无法模拟这些方法.我依靠内部细节来确定我可以模拟 TryGetValue 而不是我的测试(参见 https://github.com/aspnet/Caching/blob/c432e5827e4505c05ac7ad8ef1e3bc6bf784520b/src/MicrosoftCachingsExtractions.#L116)

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天全站免登陆