如何起订索引财产


81

我正在尝试模拟对索引属性的调用。即,我想起以下几点:

object result = myDictionaryCollection["SomeKeyValue"];

还有二传手的价值

myDictionaryCollection["SomeKeyValue"] = myNewValue;

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

有谁知道如何用起订量做到这一点?我尝试了以下方面的变体:

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

但这不能编译。

最小起订量是我想要实现的目标吗,有人能举例说明吗?


仅使用存根对象会更容易吗?设置所需的值并检查所需的索引。
索伦拼写隆德

Answers:


94

目前尚不清楚您要做什么,因为您没有显示模拟的声明。您要模拟字典吗?

MyContainer[(string s)] 无效的C#。

这样编译:

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

1
这也一样。除了新语法使用SetupSet代替ExpectGet。也适用于二传手。
tmont

1
IDictionary来自System.Collections,而不是System.Collections.Generic
upInCloud

20

灰,如果您想模拟HTTP会话,那么这段代码可以完成这项工作:

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

好人-这正是我需要的+1
伊恩·奥克斯利

1
该代码的哪一部分使被测代码使用模拟会话?是TestSuiteBase图书馆还是你自己的课?
StuperUser 2011年

那不是假的,是假的。只是说。
克里斯·孔雀

17

正如您正确发现的那样,有不同的方法SetupGet以及SetupSet分别初始化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);
    ...
  }
  ...
}

为了回答您的问题,这是一个使用基础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);

如您所见,您必须显式指定键以设置索引器二传手。详细信息在另一个SO问题中进行了描述:Moq一个索引属性,并在返回/回调中使用索引值


1
这就是我想要的!另一例无工作
菲奥娜- myaccessible.website

8

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

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

-4

看来我尝试使用最小起订量是不可能的。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.