Setting Up Mock ref Return Values in Moq

I recently received a message related to my Mocking in .NET Core Unit Tests with Moq: Getting Started Pluralsight course asking how to set the values of ref parameters.

As a (somewhat contrived) example, consider the following code:

public interface IParser
{
    bool TryParse(string value, ref int output);
}

public class Thing
{
    private readonly IParser _parser;

    public Thing(IParser parser)
    {
        _parser = parser;
    }

    public string ConvertStringIntToHex(string number)
    {
        int i = 0;

        if (_parser.TryParse(number, ref i))
        {
            return i.ToString("X");
        }

        throw new ArgumentException("The value supplied cannot be parsed into an int.", nameof(number));
    }
}

The Thing class requires an IParser to be able to work. In a test, a mocked version of an IParser can be created by Moq as the following initial test demonstrates:

[Fact]
public void ReturnHex_Fail_NoSetup()
{
    var mockParser = new Mock<IParser>();

    var sut = new Thing(mockParser.Object);

    var result = sut.ConvertStringIntToHex("255"); // fails with ArgumentException

    Assert.Equal("FF", result);
}

The preceding test will fail however because the mocked TryParse has not been configured correctly, for example specifying that the method should return true.

The following modified test attempts to fix this:

[Fact]
public void ReturnHex_Fail_NoRefValueSetup()
{
    var mockParser = new Mock<IParser>();
    mockParser.Setup(x => x.TryParse(It.IsAny<string>(), ref It.Ref<int>.IsAny))
              .Returns(true);

    var sut = new Thing(mockParser.Object);

    var result = sut.ConvertStringIntToHex("255");

    Assert.Equal("FF", result); // Fails, actual result == 0
}

In the preceding code, the return value is being set, but nowhere is the ref int output “return value” being configured.

In the following test the Callback method is used to set the ref value. To be able to do this, a delegate must first be defined that matches the signature of the mocked method that contains the ref parameter. Once this delegate is defined it can be used in the Callback method as the following code demonstrates:

// Define a delegate that can be used to set the ref value in the mocked TryParse method 
delegate void MockTryParseCallback(string number, ref int output);

[Fact]
public void ReturnHex()
{
    var mockParser = new Mock<IParser>();
    mockParser.Setup(x => x.TryParse("255", ref It.Ref<int>.IsAny)) // When the TryParse method is called with 255
              .Callback(new MockTryParseCallback((string s, ref int output) => output = 255)) // Execute callback delegate and set the ref value
              .Returns(true); // Return true as the result of the TryParse method

    var sut = new Thing(mockParser.Object);

    var result = sut.ConvertStringIntToHex("255");

    Assert.Equal("FF", result);
}

If you’ve never used Moq or want to learn more about it check out the official Moq quickstart  or head over to my Pluralsight course.

Add comment

Loading