Setting out and ref args

Out and ref arguments can be set using a Returns() callback, or using When..Do.

public interface ILookup {
    bool TryLookup(string key, out string value);
}

For the interface above we can configure the return value and set the output of the second argument like this:

//Arrange
var lookup = Substitute.For<ILookup>();
lookup
    .TryLookup("hello", out Arg.Any<string>())
    .Returns(x => { 
        x[1] = "world!";
        return true;
    });

//Act
var result = lookup.TryLookup("hello", out var value);

//Assert
Assert.True(result);
Assert.AreEqual(value, "world!");

Matching after assignments

Be careful when using an argument matcher with a reference we also assign to. The assignment can cause previously matching arguments to stop matching.

var counter = 0;
var value = "";
var lookup = Substitute.For<ILookup>();
lookup
    .TryLookup("hello", out Arg.Is(value)) // value is "", matcher will check for ""
    .Returns(x => { 
        x[1] = "assigned"; // Assign to 2nd arg
        counter++;         // Count this matching call
        return true;
    });

// value is "", this will match!
lookup.TryLookup("hello", out value);
// Call matches, counter is now 1:
Assert.AreEqual(1, counter);

// value is now "assigned" but arg matcher is still looking for "", will NOT match anymore!
lookup.TryLookup("hello", out value);
// Call does NOT match anymore, counter is still 1:
Assert.AreEqual(1, counter);