使用 Moq 抛出异常模拟 IMemoryCache [英] Mock IMemoryCache with Moq throwing exception

查看:39
本文介绍了使用 Moq 抛出异常模拟 IMemoryCache的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Moq 模拟 IMemoryCache.我收到此错误:

I'm trying to mock IMemoryCache with Moq. I'm getting this error:

System.NotSupportedException"类型的异常发生在Moq.dll 但未在用户代码中处理

An exception of type 'System.NotSupportedException' occurred in Moq.dll but was not handled in user code

附加信息:表达式引用的方法不属于模拟对象:x => x.Get(It.IsAny())

Additional information: Expression references a method that does not belong to the mocked object: x => x.Get<String>(It.IsAny<String>())

我的模拟代码:

namespace Iag.Services.SupplierApiTests.Mocks
{
    public static class MockMemoryCacheService
    {
        public static IMemoryCache GetMemoryCache()
        {
            Mock<IMemoryCache> mockMemoryCache = new Mock<IMemoryCache>();
            mockMemoryCache.Setup(x => x.Get<string>(It.IsAny<string>())).Returns("");<---------- **ERROR**
            return mockMemoryCache.Object;
        }
    }
}

为什么我会收到那个错误?

Why do I get that error?

这是被测代码:

var cachedResponse = _memoryCache.Get<String>(url);

其中 _memoryCache 的类型为 IMemoryCache

如何模拟上面的 _memoryCache.Get(url) 并让它返回 null?

How do I mock the _memoryCache.Get<String>(url) above and let it return null?

编辑:如果没有 _memoryCache.Set(url, response);,我将如何做同样的事情?我不介意它返回什么,我只需要将该方法添加到模拟中,这样它在调用时就不会抛出.

Edit: How would I do the same thing but for _memoryCache.Set<String>(url, response);? I don't mind what it returns, I just need to add the method to the mock so it doesn't throw when it is called.

根据我尝试过的这个问题的答案:

Going by the answer for this question I tried:

mockMemoryCache
    .Setup(m => m.CreateEntry(It.IsAny<object>())).Returns(null as ICacheEntry);

因为在 memoryCache 扩展中它表明它在 Set 中使用了 CreateEntry.但它错误地显示对象引用未设置为对象的实例".

Because in the memoryCache extensions it shows that it uses CreateEntry inside Set. But it is erroring out with "object reference not set to an instance of an object".

推荐答案

根据 MemoryCacheExtensions.cs,

Get 扩展方法使用以下内容

The Get<TItem> extension method makes use of the following

public static TItem Get<TItem>(this IMemoryCache cache, object key) {
    TItem value;
    cache.TryGetValue<TItem>(key, out value);
    return value;
}

public static bool TryGetValue<TItem>(this IMemoryCache cache, object key, out TItem value) {
    object result;
    if (cache.TryGetValue(key, out result)) {
        value = (TItem)result;
        return true;
    }

    value = default(TItem);
    return false;
}

请注意,它本质上是使用 TryGetValue(Object, out Object) 方法.

Notice that essentially it is using the TryGetValue(Object, out Object) method.

鉴于用 Moq 模拟扩展方法是不可行的,请尝试模拟扩展方法访问的接口成员.

Given that it is not feasible to mock extension methods with Moq, Try mocking the interface members that are accessed by the extension methods.

参考 Moq 的快速入门MockMemoryCacheService 更新为为测试正确设置 TryGetValue 方法.

Referring to Moq's quickstart update MockMemoryCacheService to properly setup the TryGetValue method for the test.

public static class MockMemoryCacheService {
    public static IMemoryCache GetMemoryCache(object expectedValue) {
        var mockMemoryCache = new Mock<IMemoryCache>();
        mockMemoryCache
            .Setup(x => x.TryGetValue(It.IsAny<object>(), out expectedValue))
            .Returns(true);
        return mockMemoryCache.Object;
    }
}

来自评论

注意在模拟 TryGetValue(代替 Get)时,out 参数即使不是,也必须声明为 object.

Note that when mocking TryGetValue (in lieu of Get), the out parameter must be declared as an object even if it isn't.

例如:

int expectedNumber = 1; 
object expectedValue = expectedNumber. 

如果你不这样做,那么它将匹配一个模板化的扩展方法同名.

If you don't do this then it will match a templated extension method of the same name.

这是一个使用修改后的服务的例子,它如何模拟 memoryCache.Get(url) 并让它返回 null

Here is an example using the modified service of how to mock the memoryCache.Get<String>(url) and let it return null

[TestMethod]
public void _IMemoryCacheTestWithMoq() {
    var url = "fakeURL";
    object expected = null;

    var memoryCache = MockMemoryCacheService.GetMemoryCache(expected);

    var cachedResponse = memoryCache.Get<string>(url);

    Assert.IsNull(cachedResponse);
    Assert.AreEqual(expected, cachedResponse);
}

更新

同样的过程可以应用于看起来像这样的 Set<> 扩展方法.

public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value) {
    var entry = cache.CreateEntry(key);
    entry.Value = value;
    entry.Dispose();

    return value;
}

此方法使用了 CreateEntry 方法,该方法返回一个 ICacheEntry,该方法也被执行.因此,设置模拟以返回模拟条目以及在以下示例中

This method makes use of the CreateEntry method which returns a ICacheEntry which is also acted upon. So set up the mock to return a mocked entry as well like in the following example

[TestMethod]
public void _IMemoryCache_Set_With_Moq() {
    var url = "fakeURL";
    var response = "json string";

    var memoryCache = Mock.Of<IMemoryCache>();
    var cachEntry = Mock.Of<ICacheEntry>();

    var mockMemoryCache = Mock.Get(memoryCache);
    mockMemoryCache
        .Setup(m => m.CreateEntry(It.IsAny<object>()))
        .Returns(cachEntry);

    var cachedResponse = memoryCache.Set<string>(url, response);

    Assert.IsNotNull(cachedResponse);
    Assert.AreEqual(response, cachedResponse);
}

这篇关于使用 Moq 抛出异常模拟 IMemoryCache的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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