Mock multiple calls to the same method with Moq

I have a method that makes a series of calls to random to generate a pseudorandom alpha-numeric order number. In order to test this method I needed to call Next multiple times to generate the string, but how do you do this in Moq?

Well, Moq has the ability to take a function for the return value. I simply added an indexer in my Returns function and return a specific value for each call.

First the method that uses random and a link statement to generate a pseudo-random value:

public string GenerateOrderNumber(string prefix)  
{
    const int LENGTH = 12;
    const string CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    var rand = Container.GetInstance<IRandom>();
    var result = new string(
        Enumerable.Repeat(CHARSET, LENGTH)
                    .Select(s => s[rand.Next(s.Length)])
                    .ToArray());
    return (prefix ?? string.Empty) + result;
}

Here's the test to

[TestMethod]
public void GenerateOrderNumber_WithoutPrefix_GeneratesCorrectly()  
{
    var expected = "ABCDLMNO1234";
    var randomCall = 0;

    var mockRandom = new Mock<IRandom>();
    mockRandom.Setup(p => p.Next(36)).Returns(() =>
        {
            randomCall++;
            switch (randomCall)
            {
                case 1: return 0;
                case 2: return 1;
                case 3: return 2;
                case 4: return 3;
                case 5: return 11;
                case 6: return 12;
                case 7: return 13;
                case 8: return 14;
                case 9: return 27;
                case 10: return 28;
                case 11: return 29;
                case 12: return 30;
                default:
                    throw new ApplicationException("Unexecpted call");
            }
        });            
    Container.RegisterSingle(mockRandom.Object);

    var sut = new Order(Container);    
    var result = sut.GenerateOrderNumber(null);

    Assert.AreEqual(12, result.Length);
    Assert.AreEqual(expected, result);
}

You can see that the mock has a Returns function that increments returnCall. The switch statement allows you to return the correct result for the current call to the method. Voila!

comments powered by Disqus