Do Instead

The DoInstead method is used to replace the actual implementation of a method with a mocked one. This topic goes through a number of scenarios where the DoInstead method is useful.

The following system under test will be used for the examples in this article:

public interface IFoo 
{ 
    int Bar { get; set; } 
    string Execute(string str); 
    int Submit(int arg1, int arg2, int arg3, int arg4); 
} 
Public Interface IFoo 
    Property Bar() As Integer 
    Function Execute(ByVal str As String) As String 
    Function Submit(num1 As Integer, num2 As Integer, num3 As Integer, num4 As Integer) As Integer 
End Interface 

Assert DoInstead

Let's see how to replace a method behavior, verify its call and its return value.

[TestMethod] 
public void ShouldAssertIfItsCalledAndReturnArgument() 
{ 
    // Arrange 
    var foo = Mock.Create<IFoo>(); 
 
    bool called = false; 
 
    Mock.Arrange(() => foo.Execute(Arg.IsAny<string>())) 
              .DoInstead(() => { called = true; }) 
              .Returns((string s) => s); 
 
    // Act 
    var actual = string.Empty; 
    actual = foo.Execute("bar"); 
 
    // Assert 
    Assert.AreEqual("bar", actual); 
    Assert.IsTrue(called);     
} 
<TestMethod()> 
Public Sub ShouldAssertIfItsCalledAndReturnArgument() 
    ' Arrange 
    Dim foo = Mock.Create(Of IFoo)() 
 
    Dim called As Boolean = False 
 
    Mock.Arrange(Function() foo.Execute(Arg.AnyString)). 
        DoInstead(Sub() called = True). 
        Returns(Function(s As String) s) 
 
    ' Act 
    Dim actual = String.Empty 
    actual = foo.Execute("bar") 
 
    ' Assert 
    Assert.AreEqual("bar", actual) 
    Assert.IsTrue(called) 
End Sub 

First, we arrange with DoInstead to execute called = true; instead of the actual implementation of foo.Execute method. Also, we set up that the call should return the passed argument directly. We act by calling the foo.Execute method with argument "bar" and then verify that the method actually returns what we expect.

Assert DoInstead for Several Arguments

You can assert DoInstead for more than one argument in the method. Follows an example for asserting four arguments:

[TestMethod] 
public void ShouldReturnSumOfArguments() 
{ 
    // Arrange 
    int expected = 0; 
 
    var foo = Mock.Create<IFoo>(); 
    Mock.Arrange(() => foo.Submit(Arg.IsAny<int>(), Arg.IsAny<int>(), Arg.IsAny<int>(), Arg.IsAny<int>())) 
        .DoInstead((int arg1, int arg2, int arg3, int arg4) => { expected = arg1 + arg2 + arg3 + arg4; }); 
 
    // Act 
    foo.Submit(10, 10, 10, 10); 
 
    // Assert 
    Assert.AreEqual(40, expected); 
} 
<TestMethod()> 
Public Sub ShouldReturnSumOfArguments() 
    ' Arrange 
    Dim expected As Integer = 0 
 
    Dim foo = Mock.Create(Of IFoo)() 
    Mock.Arrange(Function() foo.Submit(Arg.AnyInt, Arg.AnyInt, Arg.AnyInt, Arg.AnyInt)). 
        DoInstead(Function(arg1 As Integer, arg2 As Integer, arg3 As Integer, arg4 As Integer) 
                      expected = arg1 + arg2 + arg3 + arg4 
                  End Function) 
 
    ' Act 
    foo.Submit(10, 10, 10, 10) 
 
    ' Assert 
    Assert.AreEqual(40, expected) 
End Sub 

Here we replace the actual implementation of the Submit method and return the sum of the specified arguments.

Assert DoInstead On Property Set

DoInstead can also be used to change the behavior of a property set. Here we arrange to set a boolean value instead of actually setting the foo.Bar property.

[TestMethod] 
public void ShouldCheckIfPropertySetIsCalledWithZero() 
{ 
    // Arrange 
    var foo = Mock.Create<IFoo>(Behavior.Strict); 
 
    bool expected = false; 
 
    Mock.ArrangeSet(() => { foo.Bar = 1; }).DoInstead(() => expected = true); 
 
    // Act 
    foo.Bar = 1; 
 
    // Assert 
    Assert.IsTrue(expected);     
} 
<TestMethod()> 
Public Sub ShouldCheckIfPropertySetIsCalledWithZero() 
    ' Arrange 
    Dim foo = Mock.Create(Of IFoo)(Behavior.Strict) 
 
    Dim expected As Boolean = False 
 
    Mock.ArrangeSet(Sub() foo.Bar = 0).DoInstead(Sub() expected = True) 
 
    ' Act 
    foo.Bar = 0 
 
    ' Assert 
    Assert.IsTrue(expected) 
End Sub 

First, we arrange with DoInstead to execute expected = true; instead of the actual implementation of foo.Bar property setter. We act by setting foo.Bar to 1 and verify that expected is true.

Notice that we use Behavior.Strict for the mocked object.

Using Parameters Passed To The Original Call In DoInstead

DoInstead can also use the parameters passed to the original call. Assume the following examples, with the methods Echo and Bar previously added to the Foo class:

public class Foo 
{ 
    public int Echo(int num) 
    { 
        return num; 
    } 
 
    public void Bar(Action action) 
    { 
        action(); 
    } 
} 
Public Class Foo 
    Public Shared Function Echo(num As Integer) As Integer 
        Throw New NotImplementedException 
    End Function 
 
    Public Sub Bar(action As Action) 
        action() 
    End Sub 
End Class 

Now, in DoInstead, we will use the integer value passed to Echo to replace the actual implementation:

[TestMethod] 
public void ShouldUseParametersPassedToOriginalCall() 
{ 
    // Arrange 
    var foo = Mock.Create<Foo>(); 
 
    int expected = 4; 
    int actual = 0; 
 
    Mock.Arrange(() => foo.Echo(Arg.AnyInt)).DoInstead((int a) => 
    { 
        actual = a; 
    }); 
 
    // Act 
    foo.Echo(expected); 
 
    // Assert 
    Assert.AreEqual(expected, actual); 
} 
<TestMethod()> 
Public Sub ShouldUseParametersPassedToOriginalCall() 
    ' Arrange 
    Dim foo = Mock.Create(Of Foo)() 
 
    Dim expected As Integer = 4 
    Dim actual As Integer = 0 
 
    Mock.Arrange(Function() foo.Echo(Arg.AnyInt)).DoInstead(Function(a As Integer) 
                                                                actual = a 
                                                            End Function) 
 
    ' Act 
    foo.Echo(expected) 
 
    ' Assert 
    Assert.AreEqual(expected, actual) 
End Sub 

In order to parameterise the DoInstead call to apply the Echo method, simply use an action in the body accepting int to access parameters passed to Echo. In the example we replace the actual implementation with actual = a;. We act by calling foo.Echo( expected ); and verify the result.

Additionaly, you can test actions passed to the DoInstead call. Look at the following example:

[TestMethod] 
public void ShouldUseActionInDoInsteadCall() 
{ 
    // Arrange 
    var foo = Mock.Create<Foo>(); 
 
    int expected = 4; 
    int actual = 0; 
 
    Mock.Arrange(() => foo.Bar(Arg.IsAny<Action>())).DoInstead((Action action) => action()); 
 
    // Act 
    foo.Bar(new Action(() => 
    { 
        actual = expected; 
    })); 
 
    // Assert 
    Assert.AreEqual(expected, actual); 
} 
<TestMethod()> 
Public Sub ShouldUseActionInDoInsteadCall() 
    ' Arrange 
    Dim foo = Mock.Create(Of Foo)() 
 
    Dim expected As Integer = 4 
    Dim actual As Integer = 0 
 
    Mock.Arrange(Sub() foo.Bar(Arg.IsAny(Of Action))).DoInstead(Function(action As Action) 
                                                                    action() 
                                                                End Function) 
 
    ' Act 
    foo.Bar(New Action(Function() 
                            actual = expected 
                        End Function)) 
 
    ' Assert 
    Assert.AreEqual(expected, actual) 
End Sub 

We act by calling foo.Bar with new Action, changing the actual variable. In DoInstead we just execute the action. Finally, we verify that our expectations are met, namely actual and expected variables have the same value.

Using out and ref Parameters Passed To The Original Call In DoInstead

In order to mock methods containing out and ref parameters, you need to specify a delegate describing your method's prototype. Here is the method we are going to mock. Note that it is virtual and the second parameter is declared as a ref parameter.

public class DoInsteadWithCustomDelegate 
{ 
    public virtual void AddTo(int arg1, ref int arg2) 
    { 
    } 
} 
Public Class DoInsteadWithCustomDelegate 
    Public Overridable Sub AddTo(arg1 As Integer, ByRef arg2 As Integer) 
    End Sub 
End Class 

The idea behind this method is to have one parameter (arg1) the value of which is added to the second parameter(arg2). As a result of the method call the value of the second parameter will have changed as long as arg1 is not 0. Let's create a test method that performs this logic using DoInstead.

[TestMethod] 
public void ShouldTakeOutValueFromDoInsteadWhenDefinedWithCustomDelegate() 
{ 
    // Arrange 
    int refArg = 1; 
 
    var mock = Mock.Create<DoInsteadWithCustomDelegate>(); 
 
    Mock.Arrange(() => mock.AddTo(10, ref refArg)).DoInstead(new RefAction<int, int>((int arg1, ref int arg2) => 
    { 
        arg2 += arg1; 
    }));  
 
    // Act 
    mock.AddTo(10, ref refArg); 
 
    // Assert 
    Assert.AreEqual(11, refArg); 
} 
<TestMethod()> 
Public Sub ShouldTakeOutValueFromDoInsteadWhenDefinedWithCustomDelegate() 
    ' Arrange 
    Dim refArg As Integer = 1 
 
    Dim DoInsteadWithCustomDelegateMock = Mock.Create(Of DoInsteadWithCustomDelegate)() 
 
 
    Mock.Arrange(Sub() DoInsteadWithCustomDelegateMock.AddTo(10, refArg)) _ 
        .DoInstead(New RefAction(Of Integer, Integer)(Sub(arg As Integer, ByRef arg2 As Integer) 
                                                          arg2 += arg 
                                                      End Sub)) 
 
    ' Act 
    DoInsteadWithCustomDelegateMock.AddTo(10, refArg) 
 
    ' Assert 
    Assert.AreEqual(11, refArg) 
End Sub 

And here is the delegate we referenced in the DoInstead call:

public delegate void RefAction<T1, T2>(T1 arg1, ref T2 arg2); 
Public Delegate Sub RefAction(Of T1, T2)(arg1 As T1, ByRef arg2 As T2) 

See Also

In this article
Not finding the help you need? Improve this article