Sequential mocking allows you to return different values on the same or different consecutive calls to one and the same type. In other words, you can set up expectations for successive calls of the same type.
In the further examples we will use the following sample code to test:
CopyC#
public interface IFoo
{
string Execute(string arg);
int Echo(int arg1);
int GetIntValue();
}
CopyVB
Public Interface IFoo
Function Execute(arg As String) As String
Function Echo(arg1 As Integer) As Integer
Function GetIntValue() As Integer
End Interface
Step by step example
Consider the above code. We have a simple interface named IFoo and it has a method named GetIntValue that returns int.
We want to make sure that on three different successive calls, it returns three different predefined values.
CopyC#
[TestMethod]
public void ShouldArrangeAndAssertInASequence()
{
var foo = Mock.Create<IFoo>();
Mock.Arrange(() => foo.GetIntValue()).Returns(0).InSequence();
Mock.Arrange(() => foo.GetIntValue()).Returns(1).InSequence();
Mock.Arrange(() => foo.GetIntValue()).Returns(2).InSequence();
int actualFirstCall = foo.GetIntValue();
int actualSecondCall = foo.GetIntValue();
int actualThirdCall = foo.GetIntValue();
Assert.AreEqual(0, actualFirstCall);
Assert.AreEqual(1, actualSecondCall);
Assert.AreEqual(2, actualThirdCall);
}
CopyVB
<TestMethod()>
Public Sub ShouldArrangeAndAssertInASequence()
Dim foo = Mock.Create(Of IFoo)()
Mock.Arrange(Function() foo.GetIntValue()).Returns(0).InSequence()
Mock.Arrange(Function() foo.GetIntValue()).Returns(1).InSequence()
Mock.Arrange(Function() foo.GetIntValue()).Returns(2).InSequence()
Dim actualFirstCall As Integer = foo.GetIntValue()
Dim actualSecondCall As Integer = foo.GetIntValue()
Dim actualThirdCall As Integer = foo.GetIntValue()
Assert.AreEqual(0, actualFirstCall)
Assert.AreEqual(1, actualSecondCall)
Assert.AreEqual(2, actualThirdCall)
End SubIn the arrange section, we setup that:
-
the first call to GetIntValue returns 0
-
the second call returns 1
-
the third call returns 2
We achieve that by just calling
InSequence() on the
Arrange. This modifier instructs Telerik JustMock to return
the expected result in the order you specify.
Note |
|---|
In this example, every subsequent call to foo.GetIntValue will result in returning the last specified arrangement, namely 2. |
Assert Sequence with a Matcher
You can arrange consecutive calls to one and the same method passing different arguments to return different values.
CopyC#
[TestMethod]
public void ShouldAssertSequentlyWithAMatchers()
{
var iFoo = Mock.Create<IFoo>();
Mock.Arrange(() => iFoo.Execute("foo")).Returns("hello").InSequence();
Mock.Arrange(() => iFoo.Execute(Arg.IsAny<string>())).Returns("bye").InSequence();
string actualFirstCall = iFoo.Execute("foo");
string actualSecondCall = iFoo.Execute("bar");
string actualThirdCall = iFoo.Execute("foobar"); ;
Assert.AreEqual("hello", actualFirstCall);
Assert.AreEqual("bye", actualSecondCall);
Assert.AreEqual("bye", actualThirdCall);
}
CopyVB
<TestMethod()>
Public Sub ShouldAssertSequentlyWithAMatchers()
Dim iFoo = Mock.Create(Of IFoo)()
Mock.Arrange(Function() iFoo.Execute("foo")).Returns("hello").InSequence()
Mock.Arrange(Function() iFoo.Execute(Arg.IsAny(Of String)())).Returns("bye").InSequence()
Dim actualFirstCall As String = iFoo.Execute("foo")
Dim actualSecondCall As String = iFoo.Execute("bar")
Dim actualThirdCall As String = iFoo.Execute("foobar")
Assert.AreEqual("hello", actualFirstCall)
Assert.AreEqual("bye", actualSecondCall)
Assert.AreEqual("bye", actualThirdCall)
End SubIn sequential mocking you can still use the power of other features, like Matchers, to write more complete and precise tests.
Important |
|---|
| Remember that if you arrange two calls, but actually perform more than two calls, all calls after the second one will return the value specified to be returned in the second arrange. |
Assert Multiple Calls with Different Matcher
To extend the previous example, we can arrange consecutive calls to methods to return different values depending on a condition specified with a matcher.
CopyC#
[TestMethod]
public void ShouldAssertMultipleCallsWithDifferentMatchers()
{
var foo = Mock.Create<IFoo>();
Mock.Arrange(() => foo.Echo(Arg.Matches<int>(x => x > 10))).Returns(10).InSequence();
Mock.Arrange(() => foo.Echo(Arg.Matches<int>(x => x > 20))).Returns(20).InSequence();
int actualFirstCall = foo.Echo(11);
int actualSecondCall = foo.Echo(21);
Assert.AreEqual(10, actualFirstCall);
Assert.AreEqual(20, actualSecondCall);
}
CopyVB
<TestMethod()>
Public Sub ShouldAssertMultipleCallsWithDifferentMatchers()
Dim foo = Mock.Create(Of IFoo)()
Mock.Arrange(Function() foo.Echo(Arg.Matches(Of Integer)(Function(x) x > 10))).Returns(10).InSequence()
Mock.Arrange(Function() foo.Echo(Arg.Matches(Of Integer)(Function(x) x > 20))).Returns(20).InSequence()
Dim actualFirstCall As Integer = foo.Echo(11)
Dim actualSecondCall As Integer = foo.Echo(21)
Assert.AreEqual(10, actualFirstCall)
Assert.AreEqual(20, actualSecondCall)
End Sub
Returns and InSequence
When using Returns you can chain calls like in the following example of InSequence alternative.
CopyC#
[TestMethod]
public void ShouldArrangeInSequencedReturns()
{
var foo = Mock.Create<IFoo>();
Mock.Arrange(() => foo.Echo(Arg.AnyInt)).Returns(10).Returns(11).MustBeCalled();
Assert.AreEqual(10, foo.Echo(1));
Assert.AreEqual(11, foo.Echo(2));
Mock.Assert(foo);
}
CopyVB
<TestMethod()>
Public Sub ShouldArrangeInSequencedReturns()
Dim foo = Mock.Create(Of IFoo)()
Mock.Arrange(Function() foo.Echo(Arg.AnyInt)).Returns(10).Returns(11).MustBeCalled()
Assert.AreEqual(10, foo.Echo(1))
Assert.AreEqual(11, foo.Echo(2))
Mock.Assert(foo)
End SubThe effect is the same as using separate arranges for the foo object. The first call will return 10 and the second - 11.
Note |
|---|
This feature is enabled when Telerik.JustMock.Helpers namespace is included. |
Refer to Returns to learn more about Returns.
See Also