I need to test the following method:
CreateOutput(IWriter writer)
{
writer.Write(type);
writer.Write(id);
writer.Write(sender);
// many more
I wrote an extension method that will assert based on order of invocation.
public static class MockExtensions
{
public static void ExpectsInOrder(this Mock mock, params Expression>[] expressions) where T : class
{
// All closures have the same instance of sharedCallCount
var sharedCallCount = 0;
for (var i = 0; i < expressions.Length; i++)
{
// Each closure has it's own instance of expectedCallCount
var expectedCallCount = i;
mock.Setup(expressions[i]).Callback(
() =>
{
Assert.AreEqual(expectedCallCount, sharedCallCount);
sharedCallCount++;
});
}
}
}
It works by taking advantage of the way that closures work with respect to scoped variables. Since there is only one declaration for sharedCallCount, all of the closures will have a reference to the same variable. With expectedCallCount, a new instance is instantiated each iteration of the loop (as opposed to simply using i in the closure). This way, each closure has a copy of i scoped only to itself to compare with the sharedCallCount when the expressions are invoked.
Here's a small unit test for the extension. Note that this method is called in your setup section, not your assertion section.
[TestFixture]
public class MockExtensionsTest
{
[TestCase]
{
// Setup
var mock = new Mock();
mock.ExpectsInOrder(
x => x.MyMethod("1"),
x => x.MyMethod("2"));
// Fake the object being called in order
mock.Object.MyMethod("1");
mock.Object.MyMethod("2");
}
[TestCase]
{
// Setup
var mock = new Mock();
mock.ExpectsInOrder(
x => x.MyMethod("1"),
x => x.MyMethod("2"));
// Fake the object being called out of order
Assert.Throws(() => mock.Object.MyMethod("2"));
}
}
public interface IAmAnInterface
{
void MyMethod(string param);
}