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!