Assigning Out/Ref Parameters in Moq

Assigning out/ref parameters in Moq

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).

Assigning out parameters in Moq for methods that return void

Maybe you simply need this:

ISomeObject so = new SomeObject(...);
yourMock.Setup(x => x.SomeFunc(out so));

Then when you use yourMock.Object in the code you test, the so instance will "magically" come out as the out parameter.

It is a little non-intuitive ("out is in"), but it works.


Addition: Not sure I understand the scenario. The following complete program works fine:

static class Program
{
static void Main()
{
// test the instance method from 'TestObject', passing in a mock as 'mftbt' argument
var testObj = new TestObject();

var myMock = new Mock<IMyFaceToBeTested>();
IMyArgFace magicalOut = new MyClass();
myMock.Setup(x => x.MyMethod(out magicalOut)).Returns(true);

testObj.TestMe(myMock.Object);
}
}

class TestObject
{
internal void TestMe(IMyFaceToBeTested mftbt)
{
Console.WriteLine("Now code to be tested is running. Calling the method");
IMyArgFace maf; // not assigned here, out parameter
bool result = mftbt.MyMethod(out maf);
Console.WriteLine("Method call completed");
Console.WriteLine("Return value was: " + result);
if (maf == null)
{
Console.WriteLine("out parameter was set to null");
}
else
{
Console.WriteLine("out parameter non-null; has runtime type: " + maf.GetType());
}
}
}

public interface IMyFaceToBeTested
{
bool MyMethod(out IMyArgFace maf);
}
public interface IMyArgFace
{
}
class MyClass : IMyArgFace
{
}

Please indicate how your situation is different, by using the names of the classes and interfaces from my example.

How do I mock an out parameter with Moq?

To do this just create a local with the desired value and use that in the out position.

int theValue = 42;
Mock<ITarget> target = ...;
target.Setup(x => x.TheMethod(out theValue));

How to set the value of an out parameter Mocked in Moq within the Return ?

The problem you are having is because the instance of the out parameter in the setup is different to the instance actually being used when exercising the test.

Taken from Moq Quickstart documentation

callbacks for methods with ref / out parameters are possible but require some work (and Moq 4.8 or later)

Create a delegate to handle the mock invocation.

 delegate IEnumerable<SomeOtherClass> GetSomethingCallback(DateTime start, DateTime end, out bool someFlag);

In the setup use It.Ref<Bar>.IsAny for the out parameter and use the delegate in the Returns expression.

mock
.Setup(_ => _.GetSomething(It.IsAny<DateTime>(), It.IsAny<DateTime>(), out It.Ref<bool>.IsAny))
.Returns(new GetSomethingCallback((DateTime start, DateTime end, out bool someFlag) => {
IEnumerable<SomeOtherClass> otherClasses = GenerateMockedData(start, end);
//Assign something to someFlag, depending on start and end
someFlag = true;
return otherClasses;
}));

The It.Ref<bool>.IsAny instructs the returns delegate to interact with the instance reference of the actual object that was passed into the mocked member.

How can I mock an out variable in c#?

I've found out my answer in a much nicer way than using callbacks/delegates.

bsonArray result = {..Whatever data you have};
State err = default;
string errorMessage = default;
mock.Setup(x => x.runQuery(It.IsAny<string>(), out result, out err, out errorMessage);

Mock up a method with ref parameter to return specific value

The mock returning false could be an indication that the arguments set up on the mock do not match what was actually passed while exercising the test.

Loosen the expectations of the mock service with It.IsAny<T>() and It.Ref<T>.IsAny argument matchers

_service
.Setup(_ => _.CallServiceFunctionTest(It.IsAny<IList<TestObject>>(), ref It.Ref<IList<TestObjectErrors>>.Any))
.Returns(true);

Note that It.Ref<T>.IsAny requires Moq 4.8 or later

Reference Moq Quickstart: Matching Arguments

For older versions, tt should be noted from the linked documentation example

// 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);

The ref will only match if the actual instances used while exercising the test are the same.

But in the controller code shown in the example, you are newing up the errors which would mean that the instance in the test would be different to what is being arranged on the mock.

So it looks like older version of Moq is unable to provide the desired behavior without some modification of the code under test

How to make Moq ignore arguments that are ref or out

As you already figured out the problem is with your ref argument.

Moq currently only support exact matching for ref arguments, which means the call only matches if you pass the same instance what you've used in the Setup. So there is no general matching so It.IsAny() won't work.

See Moq quickstart

// 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);

And Moq discussion group:

Ref matching means that the setup is matched only if the method is
called with that same instance. It.IsAny returns null, so probably
not what you're looking for.

Use the same instance in the setup as the one in the actual call, and
the setup will match.



Related Topics



Leave a reply



Submit