Using Moq to mock a method with out parameters


In my home projects I came across the need to write a unit test for a method with the following signature:

bool TryGetSubstitution(string word, out string substitution)

Mocking this using Moq is pretty straightforward:

_mockSub = "subword";
_testOrthoepedia = new Mock<IOrthoepedia>(MockBehavior.Strict);
_testOrthoepedia
    .Setup(to => to.TryGetSubstitution(It.IsAny<string>(), out _mockSub))
    .Returns(true);

But the problem with this is that, while it allows the TryGetSubstitution() method to be called, it essentially does nothing! Prior to the call _mockSub is set to "subword" and after the call _mockSub is set to "subword". No change, no variation. I needed Moq to return different values for the out parameter in different calls.

Easy, you say: in each test, before the call is made, just change the value of _mockSub to the desired return value. Wrong! The assignation of _mockSub to "subword" is bound in the call to .Setup(). Everytime you call TryGetSubstitution() the value of _mockSub is set to "subword" by Moq. You can use that to verify that TryGetSubstitution() has been called, but not to get different values back in your unit tests.

I looked online for a solution, but I found the answers both confusing, and obsolete. Among them was this one by Scott Wegner on this StackOverflow page. The code he provided looked promising and I tried it out, but it did not work. The call to InvokeMember() kept failing because SetCallbackWithArguments() no longer exists in the Moq assembly. That was disappointing.

Then, after returning to the page at least 20 times, I finally noticed the header above the code (For Moq version(sic) before 4.10), and above that he has code for later versions of Moq, like I am using (yes, I can be dense at times).

To try out this variation, I added a definition for a new delegate and changed my mock:

public delegate void CallbackDelegate(string p1, out string p2);
...
_mockSub = "subword";
_testOrthoepedia = new Mock<IOrthoepedia>(MockBehavior.Strict);
_testOrthoepedia
    .Setup(to => to.TryGetSubstitution(It.IsAny<string>(), out _mockSub))
    .Callback(new CallbackDelegate((string word, out string substitution) => substitution = word))
    .Returns(true);

… and lo and behold: each time I called TryGetSubstitution() _mockSub was changed to the value of the first parameter passed in the call.

To genericize and expand upon this in the future I have set up a new MoqDelegates class

namespace CDP.Common.Utilities.Delegates
{
    public static class MoqDelegates
    {
        public delegate void OutAction<TOut>(out TOut outVal);
        public delegate void OutAction<T1, TOut>(T1 arg1, out TOut outVal);
        public delegate void OutAction<T1, T2, TOut>(T1 arg1, T2 agr2, out TOut outVal);
    }
}

to which additional signatures can be added as needed. And to use it, I now just add the following set up to my tests’ mocks:

outVarSignature outVar = initialvalue;
ClassToMock
    .Setup(to => to.MethodToMock(p1Signature, p2Signature,..., out outVar))
    .Callback(new OutAction<p1Signature, p2Signature,..., out outVarSignature>((p1Signature p1, p2Signature p2,..., out outVarSignature pN) => {callback code}))

Hopefully, that will be enough for me, and perhaps someone else out there, to be able to expand upon and create whatever mock is needed for test cases involving out parameters.

Edit: Note that in the example MoqDelegates class I presented above, all the delegates are named OutAction. I have found it useful to give each a slightly different name in order to allow for possible conflicts in signatures.

e.g. Trying to create a new delegate in the MoqDelegates class where the 2nd of 3 parameters is an out parameter, like this:

public delegate void OutAction<T1, TOut, T3>(T1 arg1, TOut agr2, T3 arg3);

would conflict with the third delegate. To avoid this, the delegates could be named OutAction, InOutAction, InInOutAction, and the new one, InOutInAction.

namespace CDP.Common.Utilities.Delegates
{
    public static class MoqDelegates
    {
        public delegate void OutAction<TOut>(out TOut outVal);
        public delegate void InOutAction<T1, TOut>(T1 arg1, out TOut outVal);
        public delegate void InInOutAction<T1, T2, TOut>(T1 arg1, T2 agr2, out TOut outVal);
        public delegate void InOutInAction<T1, TOut, T3>(T1 arg1, TOut agr2, T3 arg3);
    }
}

Edit: If you saw previous versions of this post, you may notice that I have removed the in parameter modifier from the delegate declarations. I was so focused on getting this construct to work that I never noticed that the in modifiers were actually there. Since they do change the way that the methods operate, I decided it would be prudent to remove them from the examples. Users can add them back when the parameter needs to be passed by reference.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s