12

At the end of the question: Using Moq to set indexers in C#, there was an issue that someone highlighted a problem that I am having as well. But they did not find a solution.

Specifically, I'm trying to use the generic It.IsAny<string> as the matcher for the key and setting the value via It.IsAny<object>. When accessing via an index and setting the value, it never matches and it does not access my call back method. And so my unit tests are failing.

var stateTable = new HashTable;
var httpSession = new Mock<HttpSessionStateBase>();

//works via httpSession.Add(key, value);
httpSession.Setup(x => x.Add(It.IsAny<string>(), It.IsAny<object>()))
    .Callback((string index, object value) => {
        var i = index;
        var v = value;

            stateData[i] = v;
    });

//does not work via httpSession[key] = value;
httpSession.SetupSet(x => x[It.IsAny<string>()] = It.IsAny<object>())
    .Callback( (string index, object value) => {
        var i = index;
        var v = value;

        stateData[i] = v;
});

I'm using Moq 4.0.10827

Community
  • 1
  • 1
Digicoder
  • 1,835
  • 1
  • 12
  • 21

3 Answers3

10

In my experience this never works, you cannot use the It.IsAny as a matcher in the indexer expression. However, it will match if you put a concrete value in the indexer. For example, the following does work:

httpSession.SetupSet(x => x["someValue"] = It.IsAny<object>())
    .Callback( (string index, object value) => {
        var i = index;
        var v = value;

        stateData[i] = v;
});
Matthew Manela
  • 16,572
  • 3
  • 64
  • 66
  • I've seen some code, from someone who prefers Rhino.Mocks, and they were able to do this. I was hoping it wasn't a Moq deficiency that was preventing this. – Digicoder Jun 09 '11 at 17:58
  • I don't know about RhinoMocks but at least in Moq it seems like a deficiency – Matthew Manela Jun 09 '11 at 18:00
  • 2
    I posted a reference to this post and a sample testcase to the Moq mailing list this morning. @kzu has seen the post and it sounds like there's agreement that both this and the corresponding misleading error messages need to be fixed. – Kaleb Pederson Jun 09 '11 at 18:37
  • 2
    The issue is actually known for some time, but I can confirm the issue is still the same unfortunately. More details here: https://github.com/Moq/moq4/issues/218. – DotBert Jun 28 '17 at 13:00
2

This is what I did to verify the read.

_httpSessionStateBaseMock.VerifySet(x => x["keyname"] = It.IsAny<YourObject>(), Times.Once());

for the reads I just went with

_httpSessionStateBaseMock.Verify(x => x["keyname"],Times.Once());
Darren
  • 68,902
  • 24
  • 138
  • 144
1

I don't like it but I was able to work around it using a new inherits class. I then override the indexer and called a virtual method which can be mocked.

public class HttpSessionStateBaseProxy : HttpSessionStateBase
{
    public virtual void SetItem(string key, object value)
    {
        base[key] = value;
    }
    public override object this[string name]
    {
        get
        {
            return base[name];
        }
        set
        {
            SetItem (name, value);
        }
    }

}

and the mocking is done by :

Mock<HttpSessionStateBaseProxy> Session = new Mock<HttpSessionStateBaseProxy>(MockBehavior.Loose);
Session.CallBase = true;
Session.Setup(x => x.SetItem(It.IsAny<string>(),It.IsAny<object>()))
        .Callback<string,object>((string index, object value) =>
        {
            if (!this.SessionItems.Contains(index)) this.SessionItems.Add(index, value);
            else this.SessionItems[index] = value;


        });

        Session.Setup(s => s[It.IsAny<string>()]).Returns<string>(key =>
        {

            return this.SessionItems[key];

        });
Avi Kessler
  • 23
  • 1
  • 5