Moq - indexed property and use index value in callback / callback

I want a moq property that has an index, and I want to be able to use index values โ€‹โ€‹in a callback, just as you can use method arguments in a callback for moq'd methods. Probably the easiest way to demonstrate with an example:

public interface IToMoq { int Add(int x, int y); int this[int x] { get; set; } } Action<int, int> DoSet = (int x, int y) => { Console.WriteLine("setting this[{0}] = {1}", x, y); throw new Exception("Do I ever get called?"); }; var mock = new Mock<IToMoq>(MockBehavior.Strict); //This works perfectly mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>())) .Returns<int, int>((a, b) => a + b); //This compiles, but my callback never seems to be called mock.SetupSet(m => m[It.IsAny<int>()] = It.IsAny<int>()) .Callback(DoSet); var obj = mock.Object; Console.WriteLine("Add(3,4) => {0}", obj.Add(3, 4)); //Works perfectly obj[1] = 2; //Does not throw, why? 

Edit: To clarify, I want the callback / return method for get be Func<int,int> , and the callback / return method for set be Action<int,int> . Trying to suggest Mike, you can do this for set , but with one major limitation:

 mock.SetupSet(m => m[23] = It.IsAny<int>()) .Callback(DoSet).Verifiable(); 

The DoSet indeed called with the values (23,<any>) . Unfortunately, using It.IsAny<int>() instead of 23 seems to behave like 0 , not <any> .

Also, I could not find a way to call SetupGet with Returns , where Returns accepts Func<int,int> , which even compiles.

Can Moq be used for this?

Motivation: I'm just playing with Moq, trying to use it to provide a free API to do the interception. That is, taking into account the I interface and the X I instance, automatically create a Mock<I> proxy with the default behavior of X

It would probably be wiser to work directly with Castle DP, but I like the syntax of the Moq expression tree.

+7
c # moq indexed-properties
Apr 17 '15 at 11:02
source share
2 answers

The SetupSet method accepts a simple delegate, not an expression tree like Expression<...> , like many other Moq methods.

For this reason, Moq cannot see that you used It.IsAny . Instead, It.IsAny is called (not what we want), and Moq only sees its return value, which is default(int) , or 0 .

+1
Apr 17 '15 at 16:56
source share

Starting with Moq 4.2.1502.0911 for the .NET Framework 4.5, I found that the following behavior is true.

The problem you are working with is calling It.IsAny<T> . If you use It.IsAny<T> , the callback fails:

 [Test] public void DoesNotExecuteCallback() { // Arrange var mock = new Mock<IIndexable>(); var called = false; mock.SetupSet(m => m[It.IsAny<int>()] = It.IsAny<int>()).Callback<int,int>((x, y) => called = true); var instance = mock.Object; // Act instance[1] = 2; // Arrange Assert.That(called, Is.False); } 

But if you call it using certain parameters, it calls the callback:

 [Test] public void DoesExecuteCallback() { // Arrange var mock = new Mock<IIndexable>(); var called = false; mock.SetupSet(m => m[1] = 2).Callback<int,int>((x, y) => called = true); var instance = mock.Object; // Act instance[1] = 2; // Arrange Assert.That(called, Is.True); } 

To summarize, you should avoid using It.IsAny when trying to set up expectations for the indexer. In general, you should avoid using it because it can encourage sloppy test writing.

There are suitable use cases for It.IsAny , but without knowing the specifics, I am inclined to recommend against it.

+1
Apr 17 '15 at 13:38 on
source share



All Articles