My Adventures in Coding

February 24, 2014

C# – Mocking a method to return a different value when called a second time using Moq

Filed under: .NET,c#,Mocking,Testing — Brian @ 2:36 pm
Tags: , , , ,

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!

So for this example, first here is my example service that we will be mocking in our tests:

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; }
    }
}

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.

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 MogMethodThatReturnsADifferentValueWhenCalledASecondTimeUsingAQueue()
{
    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);

    Assert.IsNotNull(_mockSomeService.Object.GetNextStuff());
    Assert.IsNull(_mockSomeService.Object.GetNextStuff());
}

The alternative is to use a feature in Moq called Sequences 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 MogMethodThatReturnsADifferentValueWhenCalledASecondTimeUsingSequences()
{
    Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
    _mockSomeService.SetupSequence(x => x.GetNextStuff())
		    .Returns(new SomeStuff {Id = 1, Name = "Real"})
		    .Returns(null);

    Assert.IsNotNull(_mockSomeService.Object.GetNextStuff());
    Assert.IsNull(_mockSomeService.Object.GetNextStuff());
}

Throw an exception the first time a mocked method is called, return a value the second time

In this case 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. You can accomplish this by using a feature in Moq called “Callback”.

[Test]
public void MogMethodThatThrowsAnExceptionFirstTimeCalledAndAnObjectWithSecondTime()
{
    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");
	});

    Assert.Throws<Exception>(() => _mockSomeService.Object.GetNextStuff());
    Assert.IsNotNull(_mockSomeService.Object.GetNextStuff());
}

Now, it is true that you can use a Moq Sequence to return a different value each time a mocked method is called, but as far as I can tell you can only use this where the valid value is first and throwing an exception is the last item in the sequence. In my case above I explicitly wanted to test that an exception was thrown on the first call and a valid value was returned on the second call. However, if all you need to test in your code is how it handles a valid value on the first call and an exception being thrown on the second call, you can use a Sequence for your mock setup.

[Test]
public void MockMethodThatReturnsAnObjectFirstTimeCalledAndThrowsAnExceptionSecondTimeUsingSequences()
{
    Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
    _mockSomeService.SetupSequence(x => x.GetNextStuff())
	.Returns(new SomeStuff())
	.Throws<Exception>();

    Assert.IsNotNull(_mockSomeService.Object.GetNextStuff());
    Assert.Throws<Exception>(() => _mockSomeService.Object.GetNextStuff());  
}

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 MogMethodThatThrowsAnExceptionIsVoidAssertExceptionIsThrown()
{
    Mock<ISomeService> _mockSomeService = new Mock<ISomeService>();
    _mockSomeService.Setup(x => x.DoStuff()).Throws(new Exception("Failure"));

    Assert.Throws<Exception>(() => _mockSomeService.Object.DoStuff());
}

Create a free website or blog at WordPress.com.