Moq/moq4 — pull request #23 by gburgett (2012-07-26 20:16:36+00:00)
Title: Method for extracting recorded method invocations post-verify

I often find I have a need to create unit tests around a record-replay paradigm, especially when I'm working with complex objects which do not have a ToString implementation. If I have to pass a complex object to a mocked method, and I need to assert on some property of the object, my options are:

* Use matchers in a verify, ex.:
var fooMock = new Mock();
//act
fooMock.Verify(f => f.DoIt(It.Is(b => b.Value == "A Value")));

This has the downside of requiring complex matching for multiple assertions, and poor failure text if the matcher is not matched, particularly if Baz does not have an informative ToString.

* Record the value for replay later

var fooMock = new Mock();
List recordedBazs = new List();
fooMock.Setup(f => f.DoIt(It.IsAny()))
.Callback((Baz b) => recordedBazs.Add(b));
//act
foreach(Baz b in recordedBazs)
{
Assert.AreEqual("Some Value", b.Value);
}

This is preferable, but still requires significant boilerplate code. Why should I have to provide the record/replay when Moq already does that?

My solution was to have a corollary to 'Callback' that can be chained off a call to 'Verify', in order to replay the recorded method invocations. Using this method, the above could be rewritten like this:

var fooMock = new Mock();

//act
fooMock.Verify(f => f.DoIt(It.IsAny()), Times.AtLeastOnce())
.Replay((Baz b) =>
{
Assert.AreEqual("Some Value",b.Value);
});

Multiple replays can be chained, and they can be specified to only apply to a certain number of method invocations using 'Times' as a parameter. By default a 'Replay' iterates over all the recorded method invocations.