C# 如何最小起订量索引属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/340827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:51:10  来源:igfitidea点击:

How to MOQ an Indexed property

c#tddmockingmoq

提问by Ash

I am attempting to mock a call to an indexed property. I.e. I would like to moq the following:

我试图模拟对索引属性的调用。即我想最小起订量以下:

object result = myDictionaryCollection["SomeKeyValue"];

and also the setter value

以及 setter 值

myDictionaryCollection["SomeKeyValue"] = myNewValue;

I am doing this because I need to mock the functionality of a class my app uses.

我这样做是因为我需要模拟我的应用程序使用的类的功能。

Does anyone know how to do this with MOQ? I've tried variations on the following:

有谁知道如何用 MOQ 做到这一点?我尝试了以下变体:

Dictionary<string, object> MyContainer = new Dictionary<string, object>();
mock.ExpectGet<object>( p => p[It.IsAny<string>()]).Returns(MyContainer[(string s)]);

But that doesn't compile.

但这不能编译。

Is what I am trying to achieve possible with MOQ, does anyone have any examples of how I can do this?

我试图通过 MOQ 实现什么,有没有人有我如何做到这一点的例子?

采纳答案by Ash

It appears that what I was attempting to do with MOQ is not possible.

看来我试图用 MOQ 做的事情是不可能的。

Essentially I was attempting to MOQ a HTTPSession type object, where the key of the item being set to the index could only be determined at runtime. Access to the indexed property needed to return the value which was previously set. This works for integer based indexes, but string based indexes do not work.

本质上,我试图对 HTTPSession 类型的对象进行 MOQ,其中设置为索引的项的键只能在运行时确定。访问需要返回先前设置的值的索引属性。这适用于基于整数的索引,但基于字符串的索引不起作用。

回答by Mike Scott

It's not clear what you're trying to do because you don't show the declaration of the mock. Are you trying to mock a dictionary?

不清楚您要做什么,因为您没有显示模拟的声明。你是想嘲笑一本字典吗?

MyContainer[(string s)]isn't valid C#.

MyContainer[(string s)]不是有效的 C#。

This compiles:

这编译:

var mock = new Mock<IDictionary>();
mock.SetupGet( p => p[It.IsAny<string>()]).Returns("foo");

回答by wasker

Ash, if you want to have HTTP Session mock, then this piece of code does the job:

Ash,如果你想模拟 HTTP Session,那么这段代码就可以完成这项工作:

/// <summary>
/// HTTP session mockup.
/// </summary>
internal sealed class HttpSessionMock : HttpSessionStateBase
{
    private readonly Dictionary<string, object> objects = new Dictionary<string, object>();

    public override object this[string name]
    {
        get { return (objects.ContainsKey(name)) ? objects[name] : null; }
        set { objects[name] = value; }
    }
}

/// <summary>
/// Base class for all controller tests.
/// </summary>
public class ControllerTestSuiteBase : TestSuiteBase
{
    private readonly HttpSessionMock sessionMock = new HttpSessionMock();

    protected readonly Mock<HttpContextBase> Context = new Mock<HttpContextBase>();
    protected readonly Mock<HttpSessionStateBase> Session = new Mock<HttpSessionStateBase>();

    public ControllerTestSuiteBase()
        : base()
    {
        Context.Expect(ctx => ctx.Session).Returns(sessionMock);
    }
}

回答by JustEngland

Its not that difficult but it took a little bit to find it :)

它不是那么难,但花了一点时间才找到它:)

var request = new Moq.Mock<HttpRequestBase>();
request.SetupGet(r => r["foo"]).Returns("bar");

回答by Vitaliy Ulantikov

As you correctly spotted, there are distinct methods SetupGetand SetupSetto initialize getters and setters respectively. Although SetupGetis intended to be used for properties, not indexers, and will not allow you handling key passed to it. To be precise, for indexers SetupGetwill call Setupanyway:

正如您正确发现的,有不同的方法SetupGetSetupSet分别初始化 getter 和 setter。虽然SetupGet旨在用于属性,而不是索引器,并且不允许您处理传递给它的键。准确地说,索引器无论如何SetupGet都会调用Setup

internal static MethodCallReturn<T, TProperty> SetupGet<T, TProperty>(Mock<T> mock, Expression<Func<T, TProperty>> expression, Condition condition) where T : class
{
  return PexProtector.Invoke<MethodCallReturn<T, TProperty>>((Func<MethodCallReturn<T, TProperty>>) (() =>
  {
    if (ExpressionExtensions.IsPropertyIndexer((LambdaExpression) expression))
      return Mock.Setup<T, TProperty>(mock, expression, condition);
    ...
  }
  ...
}

To answer your question, here is a code sample using underlying Dictionaryto store values:

为了回答您的问题,这里是一个使用底层Dictionary存储值的代码示例:

var dictionary = new Dictionary<string, object>();

var applicationSettingsBaseMock = new Mock<SettingsBase>();
applicationSettingsBaseMock
    .Setup(sb => sb[It.IsAny<string>()])
    .Returns((string key) => dictionary[key]);
applicationSettingsBaseMock
    .SetupSet(sb => sb["Expected Key"] = It.IsAny<object>())
    .Callback((string key, object value) => dictionary[key] = value);

As you can see, you have to explicitly specify key to set up indexer setter. Details are described in another SO question: Moq an indexed property and use the index value in the return/callback

如您所见,您必须明确指定键来设置索引器设置器。详细信息在另一个 SO 问题中描述:Moq an indexed property and use the index value in the return/callback