397

Is it possible to assign an out/ref parameter using Moq (3.0+)?

I've looked at using Callback(), but Action<> does not support ref parameters because it's based on generics. I'd also preferably like to put a constraint (It.Is) on the input of the ref parameter, though I can do that in the callback.

I know that Rhino Mocks supports this functionality, but the project I'm working on is already using Moq.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
Richard Szalay
  • 83,269
  • 19
  • 178
  • 237
  • 5
    This Q & A is about Moq 3. Moq 4.8 has much improved support for by-ref parameters, ranging from an `It.IsAny()`-like matcher (`ref It.Ref.IsAny`) to support for setting up `.Callback()` and `.Returns()` via a custom delegate types matching the method signature. Protected methods are equally supported. See e.g. [my answer below](https://stackoverflow.com/a/47723362/240733). – stakx - no longer contributing Dec 08 '17 at 22:59
  • You can use out It.Ref.Isany for any method which uses out parameter. For example: moq.Setup(x => x.Method(out It.Ref.IsAny).Returns(TValue); – MikBTC Jan 09 '20 at 22:51

15 Answers15

403

For 'out', the following seems to work for me.

public interface IService
{
    void DoSomething(out string a);
}

[TestMethod]
public void Test()
{
    var service = new Mock<IService>();
    var expectedValue = "value";
    service.Setup(s => s.DoSomething(out expectedValue));

    string actualValue;
    service.Object.DoSomething(out actualValue);
    Assert.AreEqual(expectedValue, actualValue);
}

I'm guessing that Moq looks at the value of 'expectedValue' when you call Setup and remembers it.

For ref, I'm looking for an answer also.

I found the following QuickStart guide useful: https://github.com/Moq/moq4/wiki/Quickstart

Warren Seine
  • 2,311
  • 2
  • 25
  • 38
Craig Celeste
  • 12,207
  • 10
  • 42
  • 49
  • 7
    I think the problem I had was that where is no method of _assigning_ the out/ref params from the method `Setup` – Richard Szalay Jun 29 '10 at 05:45
  • 1
    I don't have a solution for assigning a ref parameter. This example does assign a value of "output value" to 'b'. Moq doesn't execute the Expression you pass to Setup, it analyzes it and realizes that you are providing 'a' for an output value, so it looks at the present value of 'a' and remembers it for subsequent calls. – Craig Celeste Jun 29 '10 at 15:39
  • See also the out and ref examples at: http://code.google.com/p/moq/wiki/QuickStart – TrueWill Dec 08 '10 at 20:16
  • 10
    This won't work for me when the Mocked interface method is executed in a different scope that has its own referenced output variable (for example inside the method of another class.) The example given above is convenient because execution occurs in the same scope as the mock setup, however it's too simple to solve all scenarios. Support for explicit handling of the out/ref value is weak in moq (as said by somebody else, handled at execution time). – John K Mar 22 '11 at 22:43
  • 2
    +1: this is a helpful answer. But: if the out parameter type is a class rather then a build-in type like string - I don't believe this will work. Tried it today. The mock object simulates the call and returns a null via the "out" parameter. – azheglov Apr 18 '11 at 21:15
  • 2
    @azheglov No, it works with `out` parameter of any type. Are you sure your `Setup` was matched correctly? Otherwise, if you has a loose mock, it may just use the default behavior when no `Setup` is relevant. Use `MockBehavior.Strict` if you want to be sure Moq does not fall back to an empty implementation because it decides that no `Setup` matches. – Jeppe Stig Nielsen Apr 03 '17 at 10:51
  • 1
    @JohnK No, it does not depend on such scope. The lambda arrow `=>` used for created the expression tree will __close over__ or __capture__ the local variable `expectedValue`. There will be no scope problem. The Moq framework can inspect the expression tree, and find the value of the captured variable. – Jeppe Stig Nielsen Apr 03 '17 at 10:54
192

Moq version 4.8 (or later) has much improved support for by-ref parameters:

public interface IGobbler
{
    bool Gobble(ref int amount);
}

delegate void GobbleCallback(ref int amount);     // needed for Callback
delegate bool GobbleReturns(ref int amount);      // needed for Returns

var mock = new Mock<IGobbler>();
mock.Setup(m => m.Gobble(ref It.Ref<int>.IsAny))  // match any value passed by-ref
    .Callback(new GobbleCallback((ref int amount) =>
     {
         if (amount > 0)
         {
             Console.WriteLine("Gobbling...");
             amount -= 1;
         }
     }))
    .Returns(new GobbleReturns((ref int amount) => amount > 0));

int a = 5;
bool gobbleSomeMore = true;
while (gobbleSomeMore)
{
    gobbleSomeMore = mock.Object.Gobble(ref a);
}

The same pattern works for out parameters.

It.Ref<T>.IsAny also works for C# 7 in parameters (since they are also by-ref).

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
  • 2
    this is the solution, this let you have any input as ref, exactly as it would work for non ref input. This is a very nice improved support indeed – grathad Jan 12 '18 at 02:41
  • 14
    This same solution doesn't work for `out` though, does it? – ATD May 16 '19 at 16:39
  • 2
    @ATD partly yes. Declare a delegate with the out parameter and assign the value in the callback with the syntax from above – royalTS Jul 25 '19 at 07:06
  • 3
    worth mentioning that if the function you're mocking has more arguments, then the callback signature should follow the same pattern (not just the ref/out parameter) – Yoav Feuerstein Jun 08 '20 at 09:19
105

EDIT: In Moq 4.10, you can now pass a delegate that has an out or ref parameter directly to the Callback function:

mock
  .Setup(x=>x.Method(out d))
  .Callback(myDelegate)
  .Returns(...); 

You will have to define a delegate and instantiate it:

...
.Callback(new MyDelegate((out decimal v)=>v=12m))
...

For Moq version before 4.10:

Avner Kashtan provides an extension method in his blog which allows setting the out parameter from a callback: Moq, Callbacks and Out parameters: a particularly tricky edge case

The solution is both elegant and hacky. Elegant in that it provides a fluent syntax that feels at-home with other Moq callbacks. And hacky because it relies on calling some internal Moq APIs via reflection.

The extension method provided at the above link didn't compile for me, so I've provided an edited version below. You'll need to create a signature for each number of input parameters you have; I've provided 0 and 1, but extending it further should be simple:

public static class MoqExtensions
{
    public delegate void OutAction<TOut>(out TOut outVal);
    public delegate void OutAction<in T1,TOut>(T1 arg1, out TOut outVal);

    public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, TOut>(this ICallback<TMock, TReturn> mock, OutAction<TOut> action)
        where TMock : class
    {
        return OutCallbackInternal(mock, action);
    }

    public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, T1, TOut>(this ICallback<TMock, TReturn> mock, OutAction<T1, TOut> action)
        where TMock : class
    {
        return OutCallbackInternal(mock, action);
    }

    private static IReturnsThrows<TMock, TReturn> OutCallbackInternal<TMock, TReturn>(ICallback<TMock, TReturn> mock, object action)
        where TMock : class
    {
        mock.GetType()
            .Assembly.GetType("Moq.MethodCall")
            .InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock,
                new[] { action });
        return mock as IReturnsThrows<TMock, TReturn>;
    }
}

With the above extension method, you can test an interface with out parameters such as:

public interface IParser
{
    bool TryParse(string token, out int value);
}

.. with the following Moq setup:

    [TestMethod]
    public void ParserTest()
    {
        Mock<IParser> parserMock = new Mock<IParser>();

        int outVal;
        parserMock
            .Setup(p => p.TryParse("6", out outVal))
            .OutCallback((string t, out int v) => v = 6)
            .Returns(true);

        int actualValue;
        bool ret = parserMock.Object.TryParse("6", out actualValue);

        Assert.IsTrue(ret);
        Assert.AreEqual(6, actualValue);
    }



Edit: To support void-return methods, you simply need to add new overload methods:

public static ICallbackResult OutCallback<TOut>(this ICallback mock, OutAction<TOut> action)
{
    return OutCallbackInternal(mock, action);
}

public static ICallbackResult OutCallback<T1, TOut>(this ICallback mock, OutAction<T1, TOut> action)
{
    return OutCallbackInternal(mock, action);
}

private static ICallbackResult OutCallbackInternal(ICallback mock, object action)
{
    mock.GetType().Assembly.GetType("Moq.MethodCall")
        .InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock, new[] { action });
    return (ICallbackResult)mock;
}

This allows testing interfaces such as:

public interface IValidationRule
{
    void Validate(string input, out string message);
}

[TestMethod]
public void ValidatorTest()
{
    Mock<IValidationRule> validatorMock = new Mock<IValidationRule>();

    string outMessage;
    validatorMock
        .Setup(v => v.Validate("input", out outMessage))
        .OutCallback((string i, out string m) => m  = "success");

    string actualMessage;
    validatorMock.Object.Validate("input", out actualMessage);

    Assert.AreEqual("success", actualMessage);
}
Scott Wegner
  • 7,263
  • 2
  • 39
  • 55
  • Great answer, but I cannot get it to work with a void return type? E.g . method signature void TryParse(string token, out int value); – Wilbert Nov 18 '13 at 11:36
  • I created a new question for that [here](http://stackoverflow.com/questions/20046963/assigning-out-parameters-in-moq-for-methods-that-return-void). – Wilbert Nov 18 '13 at 11:46
  • 5
    @Wilbert, I've updated my answer with additional overloads for void-return functions. – Scott Wegner Nov 19 '13 at 18:49
  • +1 Thanks, that was helpful. I just had to implement the whole delegate signature with multiple in/out parameters, but with success – thmshd Jul 30 '14 at 15:08
  • 2
    I've been using this solution in our test suite and had been working. However since updating to Moq 4.10, it no longer does. – Ristogod Sep 13 '18 at 15:05
  • 2
    It looks like it was broken in this commit https://github.com/moq/moq4/commit/a605c281b812ab83d829e40018c37f00b6de52c6. Maybe's there a better way to do this now? – sparkplug Sep 14 '18 at 04:18
  • 2
    fyi in Moq4 the MethodCall is now a property of the setup, so the guts of OutCallbackInternal above changes to `var methodCall = mock.GetType().GetProperty("Setup").GetValue(mock); mock.GetType().Assembly.GetType("Moq.MethodCall") .InvokeMember("SetCallbackResponse", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, methodCall, new[] { action });` – mike mckechnie Nov 10 '18 at 15:42
  • 1
    @Ristogod, with the update to Moq 4.10, you can now pass a delegate that has an out or ref parameter directly to the Callback function: `mock.Setup(x=>x.Method(out d)).Callback(myDelegate).Returns(...);` You will have to define a delegate and instantiate it: `...Callback(new MyDelegate((out decimal v)=>v=12m))...;` – esteuart Nov 29 '18 at 02:22
  • @esteuart thanks; I've incorporated this into the answer. – Scott Wegner Nov 29 '18 at 20:55
58

This is documentation from Moq site:

// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);


// ref arguments
var instance = new Bar();
// Only matches if the ref argument to the invocation is the same instance
mock.Setup(foo => foo.Submit(ref instance)).Returns(true);
Kosau
  • 1,373
  • 12
  • 12
  • 9
    This is basically the same as Parched's answer and has the same limitation, in that it cannot change the out value depending on the input nor can it respond to ref parameters. – Richard Szalay Sep 30 '11 at 11:47
  • @Richard Szalay, You might, but you would need to have separate setups with separate "outString" parameters – Sielu Sep 09 '16 at 14:43
22

Building on Billy Jakes awnser, I made a fully dynamic mock method with an out parameter. I'm posting this here for anyone who finds it usefull.

// Define a delegate with the params of the method that returns void.
delegate void methodDelegate(int x, out string output);

// Define a variable to store the return value.
bool returnValue;

// Mock the method: 
// Do all logic in .Callback and store the return value.
// Then return the return value in the .Returns
mockHighlighter.Setup(h => h.SomeMethod(It.IsAny<int>(), out It.Ref<int>.IsAny))
  .Callback(new methodDelegate((int x, out int output) =>
  {
    // do some logic to set the output and return value.
    output = ...
    returnValue = ...
  }))
  .Returns(() => returnValue);
Martijn
  • 739
  • 9
  • 26
16

Seems like it is not possible out of the box. Looks like someone attempted a solution

See this forum post http://code.google.com/p/moq/issues/detail?id=176

this question Verify value of reference parameter with Moq

Community
  • 1
  • 1
Gishu
  • 134,492
  • 47
  • 225
  • 308
  • Thanks for the confirmation. I had actually found those two links in my searching, but also noticed that Moq lists one of it's features as "supporting ref/out parameters", so I wanted to be sure. – Richard Szalay Jul 01 '09 at 12:22
10

In VS2022 you can simply do:

foo.Setup(e => e.TryGetValue(out It.Ref<ExampleType>.IsAny))
    .Returns((ref ExampleType exampleType) => {
        exampleType = new ExampleType();
        return true;
})
derekbaker783
  • 8,109
  • 4
  • 36
  • 50
Red Riding Hood
  • 1,932
  • 1
  • 17
  • 36
5

I'm sure Scott's solution worked at one point,

But it's a good argument for not using reflection to peek at private apis. It's broken now.

I was able to set out parameters using a delegate

      delegate void MockOutDelegate(string s, out int value);

    public void SomeMethod()
    {
        ....

         int value;
         myMock.Setup(x => x.TryDoSomething(It.IsAny<string>(), out value))
            .Callback(new MockOutDelegate((string s, out int output) => output = userId))
            .Returns(true);
    }
2

To return a value along with setting ref parameter, here is a piece of code:

public static class MoqExtensions
{
    public static IReturnsResult<TMock> DelegateReturns<TMock, TReturn, T>(this IReturnsThrows<TMock, TReturn> mock, T func) where T : class
        where TMock : class
    {
        mock.GetType().Assembly.GetType("Moq.MethodCallReturn`2").MakeGenericType(typeof(TMock), typeof(TReturn))
            .InvokeMember("SetReturnDelegate", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock,
                new[] { func });
        return (IReturnsResult<TMock>)mock;
    }
}

Then declare your own delegate matching the signature of to-be-mocked method and provide your own method implementation.

public delegate int MyMethodDelegate(int x, ref int y);

    [TestMethod]
    public void TestSomething()
    {
        //Arrange
        var mock = new Mock<ISomeInterface>();
        var y = 0;
        mock.Setup(m => m.MyMethod(It.IsAny<int>(), ref y))
        .DelegateReturns((MyMethodDelegate)((int x, ref int y)=>
         {
            y = 1;
            return 2;
         }));
    }
Victor Mukherjee
  • 10,487
  • 16
  • 54
  • 97
  • Does this work when you don't have access to the variable that is going to be passed in as y? I have a function that takes two ref arguments to DayOfWeek. I need to set both of these to a particular day in the mock stub and the third argument is a mock database context. But the delegate method just isn't being called. It looks like Moq would be expecting to match the local y being passed ot your "MyMethod" function. Is that how this works for your example? Thx. – Greg Veres May 01 '17 at 00:10
1

I struggled with this for an hour this afternoon and could not find an answer anywhere. After playing around on my own with it I was able to come up with a solution which worked for me.

string firstOutParam = "first out parameter string";
string secondOutParam = 100;
mock.SetupAllProperties();
mock.Setup(m=>m.Method(out firstOutParam, out secondOutParam)).Returns(value);

The key here is mock.SetupAllProperties(); which will stub out all of the properties for you. This may not work in every test case scenario, but if all you care about is getting the return value of YourMethod then this will work fine.

maxshuty
  • 9,708
  • 13
  • 64
  • 77
1

I struggled with many of the suggestions here before I simple created an instance of a new 'Fake' class that implements whatever interface you are trying to Mock out. Then you can simply set the value of the out parameter with the method itself.

Casey O'Brien
  • 407
  • 2
  • 6
  • 15
1

The following is an example that is working.

[Fact]
public void DeclineLowIncomeApplicationsOutDemo()
{
    var mockValidator = new Mock<IFrequentFlyerNumberValidator>();

    var isValid = true; // Whatever we set here, thats what we will get.

    mockValidator.Setup(x => x.IsValid(It.IsAny<string>(), out isValid));

    var sut = new CreditCardApplicationEvaluator(mockValidator.Object);

    var application = new CreditCardApplication
    {
        GrossAnnualIncome = 19_999,
        Age = 42
    };

    var decision = sut.EvaluateUsingOut(application);

    Assert.Equal(CreditCardApplicationDecision.AutoDeclined, decision);
}

public interface IFrequentFlyerNumberValidator
{
    bool IsValid(string frequentFlyerNumber);
    void IsValid(string frequentFlyerNumber, out bool isValid);
}

Note there is no Returs in the setup as there is no returns.

VivekDev
  • 20,868
  • 27
  • 132
  • 202
0

This can be a solution .

[Test]
public void TestForOutParameterInMoq()
{
  //Arrange
  _mockParameterManager= new Mock<IParameterManager>();

  Mock<IParameter > mockParameter= new Mock<IParameter >();
  //Parameter affectation should be useless but is not. It's really used by Moq 
  IParameter parameter= mockParameter.Object;

  //Mock method used in UpperParameterManager
  _mockParameterManager.Setup(x => x.OutMethod(out parameter));

  //Act with the real instance
  _UpperParameterManager.UpperOutMethod(out parameter);

  //Assert that method used on the out parameter of inner out method are really called
  mockParameter.Verify(x => x.FunctionCalledInOutMethodAfterInnerOutMethod(),Times.Once());

}
Fabrice
  • 9
  • 1
  • 1
    This is basically the same as Parched's answer and has the same limitation, in that it cannot change the out value depending on the input nor can it respond to ref parameters. – Richard Szalay Sep 01 '11 at 08:53
0

Something like that does the trick:

method to be mocked would be

public bool GenerateClient(out Client client);

Then the mock part would be:

Client client = new Client();
clintMockBll
.Setup(x => x.GenerateClient(out client))
.Returns((Client client1) =>
{
   client = new Client(){Name="Something"};
   return true;
});
0

An enhancement on Craig Celeste's answer for any who wish to use It.IsAny for the out parameter:

public interface IService
{
    void DoSomething(out string a);
}

[TestMethod]
public void Test()
{
    var service = GetService();
    string actualValue;
    service.Object.DoSomething(out actualValue);
    Assert.AreEqual(expectedValue, actualValue);
}

private IService GetService()
{
    var service = new Mock<IService>();
    var anyString = It.IsAny<string>();
    service.Setup(s => s.DoSomething(out anyString))
        .Callback((out string providedString) => 
        {
            providedString = "SomeValue";
        });
    return service.Object;
}

You could also use Returns instead of Callback if your method also needs to return something.

YungDeiza
  • 3,128
  • 1
  • 7
  • 32