devlooped / moq

The most popular and friendly mocking framework for .NET
Other
5.92k stars 801 forks source link

Implement raising of non-virtual events via `Mock<T>.Raise` #457

Closed stakx closed 6 years ago

stakx commented 7 years ago

This unit test in UnitTests/MockedEventsFixture.cs has been disabled forever, but its presence suggests that Moq was at some point in the past supposed to be able to raise non-virtual events via Mock<T>.Raise.:

[Fact(Skip = "Events on non-virtual events not supported yet")]
public void EventRaisingFailsOnNonVirtualEvent()
{
   var mock = new Mock<WithEvent>();
   var raised = false;
   mock.Object.ClassEvent += delegate { raised = true; };
   mock.Raise(x => x.ClassEvent += null, EventArgs.Empty);
   Assert.True(raised);
}
stakx commented 6 years ago

This cannot be implemented in a straightforward manner because expression trees do not allow assignment operators such as += or -=. The delegate passed to Raise would either have to be decompiled to retrieve such an expression (which in turn requires .NET Standard 2.0 while we're still at 1.3) or a major API change (e.g. using nameof instead of a lambda).

Neither alternative seems a particularly good fit for Moq 4 so this is perhaps better left unimplemented for the time being. Once Moq targets .NET Standard 2.0, or C# expression lambdas become less restrictive regarding assignments, we can consider doing this once again.

stakx commented 5 years ago

Moq has since gotten a new delegate reconstruction algorithm, which however still isn't based on IL decompilation as I assumed (above) it might be. (This is what would have required .NET Standard 2.0.) So we still can't support this scenario for the forseeable future.