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

9 Comments »

  1. Good to know how to mock a method to return different values. Thanks.

    Comment by Excoded — August 5, 2014 @ 1:31 pm | Reply

  2. great thanks mate

    Comment by sadddddddd — February 25, 2015 @ 7:56 am | Reply

  3. […] Mocking – по-ефективни тестови програми(unit tests). Създаваме фалшив обект(прокси), който се представя за нашия обект и има същото поведение, като по този начин опростяваме възможността за тестване. В този обект(например клас, който наследява даден интерфейс) можем да не имплементираме всички методи на интерфейса, а само този метод, който искаме да тестваме. По-подробна информация за Moq можете да намерите ТУК. Можете да инсталирате Moq за Visual Studio от NuGet package manager. Още информация за използването на Moq: ТУК и ТУК. […]

    Pingback by Inversion of Control | mAgdalena70petrovA — March 6, 2015 @ 3:37 am | Reply

  4. Thanks mate. It helped me a lot.

    Comment by Coder — March 26, 2015 @ 10:25 am | Reply

  5. Great article, been searching high and low for this solution!

    Comment by Pete C. — March 27, 2015 @ 8:23 am | Reply

  6. Another option would be to overwrite the Setup in the callback. For example:

    _mockSomeService
    .Setup(x => x.GetNextStuff())
    .Callback(() => _mockSomeService.Setup(x => x.GetNextStuff()).Returns(() => new SomeStuff {Id = 1, Name = “Real”})
    .Throws(new Exception(“Failure”))

    The first time it is called it will throw the exception, but it’ll also call the Callback which overwrites the setup to return a response the next time it is called.

    This way you don’t need the additional ‘calls’ closure, you just use the _mockSomeService as a closure. You could also chain different behaviours this way and change the order in which things happen.

    Comment by Owain Williams — April 17, 2015 @ 6:47 am | Reply

  7. This article came in handy for me at work the last couple of days. Thanks for posting it!

    Comment by xcodula — June 16, 2015 @ 11:44 am | Reply

  8. I found it very useful. Thanks so much for sharing

    Comment by rafeek — April 14, 2016 @ 7:45 am | Reply

  9. You really helped me 🙂 Thanks for sharing such usefull subject.

    Comment by Alex Konstantinov — May 18, 2016 @ 1:48 pm | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: