Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a mock throw an exception the first time and return a value the second one

I am using Moq as my mocking framework and I need to test a class that when a specific type of exception is run it will keep trying until the situation is resolved once that happens the execution finishes.

So what I need is something similar to:

myMock = Mock<IFoo>();

myMock.Setup(m => m.Excecute()).Throws<SpecificException>();
myMock.Setup(m => m.Execute());

var classUnderTest = MyClass(myMock);
classUnderTest.DoSomething();

Assert.AreEqual(expected, classUnderTest.Result);

Thanks for any help you can give.

like image 524
Sergio Romero Avatar asked Oct 27 '11 17:10

Sergio Romero


3 Answers

This is one way, based on the Moq QuickStart example of returning different values on each invocation.

var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
    .Returns(() => calls)
    .Callback(() =>
     {
        calls++;
        if (calls == 1)
        {
            throw new InvalidOperationException("foo");
        }
     });

try
{
    Console.WriteLine(mock.Object.GetCountThing());
}
catch (InvalidOperationException)
{
    Console.WriteLine("Got exception");
}

Console.WriteLine(mock.Object.GetCountThing());

If the method returns void, use:

var myMock = new Mock<IFoo>();
bool firstTimeExecuteCalled = true;

myMock.Setup(m => m.Execute())
      .Callback(() =>
       {
            if (firstTimeExecuteCalled)
            {
                firstTimeExecuteCalled = false;
                throw new SpecificException();
            }
       });

try
{
    myMock.Object.Execute();
}
catch (SpecificException)
{
    // Would really want to call Assert.Throws instead of try..catch.
    Console.WriteLine("Got exception");
}

myMock.Object.Execute();
Console.WriteLine("OK!");
like image 134
TrueWill Avatar answered Oct 18 '22 20:10

TrueWill


https://github.com/Moq/moq4/wiki/Quickstart#miscellaneous

Setting up a member to return different values / throw exceptions on sequential calls:

var mock = new Mock<IFoo>();
mock.SetupSequence(f => f.GetCount())
    .Returns(3)  // will be returned on 1st invocation
    .Returns(2)  // will be returned on 2nd invocation
    .Returns(1)  // will be returned on 3rd invocation
    .Returns(0)  // will be returned on 4th invocation
    .Throws(new InvalidOperationException());  // will be thrown on 5th invocation
like image 33
Robert Taylor Avatar answered Oct 18 '22 20:10

Robert Taylor


Why not actually write your own test object that does this? If it's just going to be used for testing ie something like:

public class Mock : IFoo
{
     private int _calls;

     public Mock()
     {
         _calls = 0;
     }

     public int Execute()
     {
         _calls++;

         if (_calls == 1)
             throw new Exception();

         return value;

     }

}
like image 41
Kevin Holditch Avatar answered Oct 18 '22 20:10

Kevin Holditch