Mocking indexer setters with Moq

(c) Bertrand Le Roy 2004 I quite like MoQ because it makes sense for me. Shamefully, I’ve always had some trouble understanding test code that was using mocks built with other frameworks. With MoQ, I can just grok it for some reason. It’s just super-clear to me. It doesn’t mean I have any idea how it really works but for now I’m just happy with the magic.

Anyway, yesterday I wanted to check that a controller action was setting some Application variable (let’s not get into the debate on whether or not it should do that at all). Something like this:

application["foo"] = new Foo();

Now how do I enable the object to be set by the tested code? Well, that one is easy, I can use SetupSet on indexers just fine:

var mockHttpContext = new Mock<HttpContextBase>();
c => c.Application["foo"] = It.IsAny<object>());

This call tells the mock that it can accept to run code that attempts to set the “Foo” application variable with any object.

But now, what if I want to get a reference to that object from my test code in order to check the value of some of its properties?

Well, MoQ has a Callback method that you can hook to the result of any Setup call. The action that you provide it will be run whenever the setup code is called. The problem with that callback method is that its signature must match that of the setter exactly. Unfortunately, that signature is implicit. If you get it wrong, the test will fail more or less silently (it will just tell you setup failed with little details). To get this right, you need to know what the setter syntactic sugar compiles to, which kinda sucks, but the good news is that you only have to figure it out once, which I just spent some time doing for you (and for myself too, let’s be honest):

var mockHttpContext = new Mock<HttpContextBase>();
Foo map = null;
.SetupSet(c => c.Application["foo"] = It.IsAny<object>()) .Callback((string name, object m) => { map = (Foo)m; });

Because this is an indexer setter, the compiled code actually takes a name and a value, which is reflected by the signature of the callback lambda. We can now call into the code to test, knowing that when it sets our “Foo” application variable, the local “map” variable of the test code will get set. The test code can then party on the object and assert whatever it wants.

I hope this saves some time whoever is trying to do the same thing.


Comments have been disabled for this content.