I have been using Moq as my primary mocking framework in C# for several years now. Overall I really like it, the syntax is easy to read, the mock setup is straight forward, etc. However, there are a few cases I need to mock infrequently and I always forget how to do the setup. Often because I am cycling between Scala, Python, and C#. So in this post I am just listing those three cases in hopes they may help others, yet at the same time as a reference to myself!
You can download the example code from GitHub here.
Setup
The class SomeService represents a class our application will use to talk to some external service. In our tests we want to mock these service calls to test different scenarios. Here is the code we will be using in our mocking examples:
namespace MoqExample
{
public interface ISomeService
{
SomeStuff GetNextStuff();
void DoStuff();
}
public class SomeService : ISomeService
{
public SomeStuff GetNextStuff()
{
return new SomeStuff();
}
public void DoStuff()
{
}
}
public class SomeStuff
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Mock Examples
Scenario – Return a different value the second time a mocked method is called
Let’s say I have a call in a service that returns the next item to process, such as pulling in customer requests from a queue that need to be processed in order, one at a time. In this case I might want to have a test that demonstrates the application can handle two different requests back to back, or even handle the case where there is an item to process, but the next item returned is empty, meaning there is nothing left to process. If I need to test this case there are several simple ways to do this with Moq.
Option 1 – Use a Queue
The more well known approach is to just use a Queue and have the mock call Dequeue and return the result each time the mocked method is called.
[Test]
public void Mock_ShouldReturnDifferentValue_WhenCalledASecondTimeUsingQueue()
{
// Arrange
Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
var queueStuff = new Queue<SomeStuff>();
queueStuff.Enqueue(new SomeStuff { Id = 1, Name = "Real" });
queueStuff.Enqueue(null);
_mockSomeService.Setup(x => x.GetNextStuff()).Returns(queueStuff.Dequeue);
// Act
var resultOne = _mockSomeService.Object.GetNextStuff();
var resultTwo = _mockSomeService.Object.GetNextStuff();
// Assert
Assert.AreEqual("Real", resultOne.Name);
Assert.IsNull(resultTwo);
}
Option 2 – Use a Sequence
The alternative is to use the Moq feature Sequence which allows you to set multiple return values, that will be returned one at a time in order, each time the mocked method is called.
[Test]
public void Mock_ShouldReturnsDifferentValue_WhenCalledASecondTimeUsingSequences()
{
// Arrange
Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
_mockSomeService.SetupSequence(x => x.GetNextStuff())
.Returns(new SomeStuff { Id = 1, Name = "Real" })
.Returns((SomeStuff)null);
// Act
var resultOne = _mockSomeService.Object.GetNextStuff();
var resultTwo = _mockSomeService.Object.GetNextStuff();
// Assert
Assert.AreEqual("Real", resultOne.Name);
Assert.IsNull(resultTwo);
}
Scenario – Throw an exception the first time a mocked method is called, return a value the second time
In this scenario I want to test that my application will handle the case that when a call to a service throws an exception, it will retry and if it receives a valid response on the second try, process the request successfully and continue.
Option 1 – Use a Callback
You can accomplish this by using a Callback.
[Test]
public void Mock_ShouldSucceedOnSecondCall_WhenThrowsExceptionOnFirstCall()
{
// Arrange
Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
var calls = 0;
_mockSomeService.Setup(x => x.GetNextStuff())
.Returns(() => new SomeStuff { Id = 1, Name = "Real" })
.Callback(() =>
{
calls++;
if (calls == 1)
throw new Exception("Failure");
});
// Act
var resultOneException = Record.Exception(() => _mockSomeService.Object.GetNextStuff());
var resultTwo = _mockSomeService.Object.GetNextStuff();
// Assert
Assert.AreEqual("Failure", resultOneException.Message);
Assert.AreEqual("Real", resultTwo.Name);
}
Option 2 – Use a Sequence
As an alternative to using a Callback, you can use the Moq feature Sequence for your mock setup.
[Test]
public void Mock_ShouldThrowExceptionOnSecondCall_WhenSucceedsOnFirstCallUsingSequences()
{
// Arrange
Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
_mockSomeService.SetupSequence(x => x.GetNextStuff())
.Throws(new Exception("Failure"))
.Returns(new SomeStuff { Id = 1, Name = "Real" });
// Act
var resultOneException = Record.Exception(() => _mockSomeService.Object.GetNextStuff());
var resultTwo = _mockSomeService.Object.GetNextStuff();
// Assert
Assert.AreEqual("Failure", resultOneException.Message);
Assert.AreEqual("Real", resultTwo.Name);
}
Scenario – Mock a void method to throw an exception
Lets say I have some void method that normally just silently does some task for me and has no need to have a return type, such as a call to write a stat or a log entry. However, if I want to test how my application handles the case when this call throws an exception, I can use the following setup to mock this method.
[Test]
public void Mock_ShouldThrowException_WhenMockedVoidMethodIsCalled()
{
// Arrange
Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
_mockSomeService.Setup(x => x.DoStuff())
.Throws(new Exception("Failure"));
// Act
var resultException = Record.Exception(() => _mockSomeService.Object.DoStuff());
// Assert
Assert.AreEqual("Failure", resultException.Message);
}
I hope that helps!