Moq/moq4 — pull request #4 by quetzalcoatl (2012-03-22 21:10:23+00:00)
Title: Capability of mocking delegates (event handlers)

Contents:

In short, this patch adds support for 'new Mock' where DLG is derivative of System.Delegate. This should cover all possible event handlers, both concrete like PropertyChangedEventHandler, and generic like EventHandler>, but also all other delegates like System.Action<..> or System.Func<..>.

Previously it was not possible, because the delegates are in fact a compiler-generated classes with parameterized constructors, and the constructor's arguments need to meet several conditions. They couldn't be autogenerated in a standard way the Moq does, and the proxy builder crashed if given a request to make a proxy for a delegate.

The idea behind the patch is fairly simple: translate the request from mock-a-delegate into mock-a-normal-class.

Thus, if Mock detects that the T is a subclass of System.Delegate, it not now doesn't try to mock the delegate, and executes following workaround:
1) dynamically creates an minimalistic interface[1], which declares a single method, which exacly matches the delegate's type
2) it creates a mock object based on that interface, effectively calling 'new Mock< thatinterface >'
3) constructs a delegate of requested type in a classic way, specifing the newly created proxy object the delegate.Target and the interface's single method as delegate.Method

This means that the constructed delegate object is a completely normal delegate object and is not a proxy itself. The proxy is hidden in its Target/Method, and the delegate is properly usable in all normal ways: it can be invoked, used as an event handler, merged with other similar delegates, etc. The Mock relays all actions to the actual mock object, thus all Setup/Verify operations work as expected.

Notes:
[1] it is obvious that it is the delegate's type that dictates the exact shape of the generated interface; the dynamic interfaces are cached and reused

Example of use:
test if a public event was raised

// Arrange
var fakeHandler = new Mock();
var sut = new TestedObject();
sut.TheEvent += fakeHandler.Object;

// Act
// ...do something that should have an side effect of raising the event

// Assert
fakeHandler.Verify(eh => eh(sut, It.IsAny()), Times.Once());

Credits:

Over 90% of the patch was originally prepared by RoystonS...@gmail.com (-> http://code.google.com/p/moq/issues/detail?id=235#c2) for svn rev 668 (-> http://code.google.com/p/moq/source/detail?r=668).
I've updated his original patch to svn's current head (751), and also for the new repo on github. I've also added support for Mock.Get<>(), as it was overlooked in the original patch and rendered usage of 'functional-style' Mock.Of<>() useless if the mocked delegate was meant to .Verify() something.