I want a mock that returns 0 the first time, then returns 1 anytime the method is called thereafter. The problem is that if the method is called 4 times, I have to write:

mock.SetupSequence(x => x.GetNumber())
    .Returns(0)
    .Returns(1)
    .Returns(1)
    .Returns(1);

Otherwise, the method returns null.

Is there any way to write that, after the initial call, the method returns 1?


Solution 1:

The cleanest way is to create a Queue and pass .Dequeue method to Returns

.Returns(new Queue<int>(new[] { 0, 1, 1, 1 }).Dequeue);

Solution 2:

That's not particulary fancy, but I think it would work:

    var firstTime = true;

    mock.Setup(x => x.GetNumber())
        .Returns(()=>
                        {
                            if(!firstTime)
                                return 1;

                            firstTime = false;
                            return 0;
                        });

Solution 3:

Bit late to the party, but if you want to still use Moq's API, you could call the Setup function in the action on the final Returns call:

var mock = new Mock<IFoo>();
mock.SetupSequence(m => m.GetNumber())
    .Returns(4)
    .Returns(() =>
    {
        // Subsequent Setup or SetupSequence calls "overwrite" their predecessors: 
        // you'll get 1 from here on out.
        mock.Setup(m => m.GetNumber()).Returns(1);
        return 1;
    });

var o = mock.Object;
Assert.Equal(4, o.GetNumber());
Assert.Equal(1, o.GetNumber());
Assert.Equal(1, o.GetNumber());
// etc...

I wanted to demonstrate using StepSequence, but for the OP's specific case, you could simplify and have everything in a Setup method:

mock.Setup(m => m.GetNumber())
    .Returns(() =>
    {
        mock.Setup(m => m.GetNumber()).Returns(1);
        return 4;
    });

Tested everything here with [email protected] and [email protected] - passes ✔

Solution 4:

Just setup an extension method like:

public static T Denqueue<T>(this Queue<T> queue)
{
    var item = queue.Dequeue();
    queue.Enqueue(item);
    return item;
}

And then setup the return like:

var queue = new Queue<int>(new []{0, 1, 1, 1});
mock.Setup(m => m.GetNumber).Returns(queue.Denqueue);