Как MOQ индексируемое свойство - PullRequest
69 голосов
/ 04 декабря 2008

Я пытаюсь смоделировать вызов индексированного свойства. То есть Я хотел бы moq следующее:

object result = myDictionaryCollection["SomeKeyValue"];

, а также установочное значение

myDictionaryCollection["SomeKeyValue"] = myNewValue;

Я делаю это, потому что мне нужно смоделировать функциональность класса, который использует мое приложение.

Кто-нибудь знает, как это сделать с помощью MOQ? Я пробовал варианты на следующем:

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

Но это не компилируется.

Возможно ли то, что я пытаюсь достичь с помощью MOQ, есть ли у кого-нибудь примеры того, как я могу это сделать?

Ответы [ 5 ]

77 голосов
/ 11 декабря 2008

Непонятно, что ты пытаешься сделать, потому что ты не показываешь декларации макета. Вы пытаетесь издеваться над словарем?

MyContainer[(string s)] недопустимо C #.

Это компилируется:

var mock = new Mock<IDictionary>();
mock.SetupGet( p => p[It.IsAny<string>()]).Returns("foo");
20 голосов
/ 14 мая 2009

Эш, если вы хотите, чтобы 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);
    }
}
9 голосов
/ 03 июня 2016

Как вы правильно заметили, существуют различные методы SetupGet и SetupSet для инициализации геттеров и сеттеров соответственно. Хотя 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 индексированное свойство и использование значения индекса в возврате / обратном вызове

6 голосов
/ 06 мая 2015

Это не так сложно, но это заняло немного времени:)

var request = new Moq.Mock<HttpRequestBase>();
request.SetupGet(r => r["foo"]).Returns("bar");
0 голосов
/ 16 марта 2009

Похоже, что то, что я пытался сделать с MOQ, невозможно.

По сути, я пытался MOQ-объект типа HTTPSession, где ключ элемента, установленного в индекс, мог быть определен только во время выполнения. Доступ к индексированному свойству необходим для возврата значения, которое было ранее установлено. Это работает для целочисленных индексов, но строковые индексы не работают.

...