How to MOQ an Indexed property

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

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:

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?

Answers


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#.

This compiles:

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

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

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

As you correctly spotted, there are distinct methods SetupGet and SetupSet to initialize getters and setters respectively. Although SetupGet is intended to be used for properties, not indexers, and will not allow you handling key passed to it. To be precise, for indexers SetupGet will call Setup anyway:

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 Dictionary to store values:

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


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");

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

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.


Need Your Help

How can I count the occurrences of a list item?

python list count

Given an item, how can I count its occurrences in a list in Python?

Javadoc @see object method

java javadoc

I would like to link a method of another object using @see from a comment block