6
Vote

AutoMocking interfaces with events throws DynamicProxy2 exception (UPDATED)

description

(UPDATED unit test attached -- still fails after incorporating fix suggested by baxevanis with Moq v4.0.10827)
When I use AutoFixture (v2.9.2, with AutoMoqCustomization -- with Moq v 4.0.10827 and the appropriate dependentAssembly bindingRedirect) to Freeze and inject a mock of an interface that contains an event into my SUT, the following exception is thrown when my event is wired up inside the SUT:

System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.NotImplementedException : This is a DynamicProxy2 error: The interceptor attempted to 'Proceed' for method 'Void add_Fire(System.EventHandler)' which has no target. When calling method without target there is no implementation to 'proceed' to and it is the responsibility of the interceptor to mimic the implementation (set return value, out arguments etc)
at System.RuntimeMethodHandle._InvokeConstructor(IRuntimeMethodInfo method, Object[] args, ref SignatureStruct signature, RuntimeType declaringType)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
at Ploeh.AutoFixture.Kernel.MethodInvoker.Create(Object request, ISpecimenContext context)
at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.<Create>b__1(ISpecimenBuilder b)
at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext()
at System.Linq.Enumerable.<DefaultIfEmptyIterator>d__a51.MoveNext()
at System.Linq.Enumerable.FirstOrDefault(IEnumerable
1 source)
at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context)
at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.<Create>b__1(ISpecimenBuilder b)
at System.Linq.Enumerable.WhereSelectListIterator
2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at System.Linq.Enumerable.<DefaultIfEmptyIterator>d__a5
1.MoveNext()
at System.Linq.Enumerable.FirstOrDefault(IEnumerable1 source)
at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.<Create>b__1(ISpecimenBuilder b)
at System.Linq.Enumerable.WhereSelectListIterator
2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at System.Linq.Enumerable.<DefaultIfEmptyIterator>d__a5
1.MoveNext()
at System.Linq.Enumerable.FirstOrDefault(IEnumerable1 source)
at Ploeh.AutoFixture.Kernel.Postprocessor
1.Create(Object request, ISpecimenContext context)
at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.<>c__DisplayClass6.<Create>b__1(ISpecimenBuilder b)
at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext()
at System.Linq.Enumerable.<DefaultIfEmptyIterator>d__a51.MoveNext()
at System.Linq.Enumerable.FirstOrDefault(IEnumerable
1 source)
at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
at Ploeh.AutoFixture.SpecimenFactory.CreateAnonymous(ISpecimenContext context, T seed)
at Ploeh.AutoFixture.SpecimenFactory.CreateAnonymous(ISpecimenContext context)
at MyNamespace.AutoFixtureEventsExploratoryTests.ThisDoesNotWork() in AutoFixtureEventsExploratoryTests.cs: line 18
--NotImplementedException
at Castle.DynamicProxy.AbstractInvocation.ThrowOnNoTarget()
at Castle.DynamicProxy.CompositionInvocation.EnsureValidTarget()
at Castle.Proxies.Invocations.IMyEventRaisingInterface_add_Fire.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Moq.Interceptor.Intercept(ICallContext invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at MyNamespace.MyClass..ctor(IMyEventRaisingInterface trigger) in AutoFixtureEventsExploratoryTests.cs: line 51

Also, I noticed that the same test fails differently when using the exact version of Moq (matching the NuGet package's dependency) -- in this case the event simply never fires (or the registered handler in the SUT class never gets invoked, so the Assert fails.

file attachments

comments

baxevanis wrote Mar 14, 2012 at 3:55 PM

The one test that fails will pass if you change this call:
var mockTrigger = fixture.CreateAnonymous<Mock<IMyEventRaisingDependency>>();

With this one:
var mockTrigger = fixture.Freeze<Mock<IMyEventRaisingDependency>>();

You can read more about the Freeze feature here: http://blog.ploeh.dk/2010/03/17/AutoFixtureFreeze.aspx

(I downloaded the attached file and run the tests without changing the packages.)

jrnail23 wrote Mar 15, 2012 at 3:32 PM

Wow, I'm embarrassed now. I freeze mocks 100 times a day -- I have no idea why that wasn't the first thing I tried.

TBone512 wrote Jun 15, 2012 at 12:42 PM

Just to note, this appears to be related to the Moq 4.0 library. I had the same issue until I rolled my Moq assembly back to the 3.1 version that AutoFixture builds with.

ploeh wrote Jun 17, 2012 at 12:27 PM

This isn't an AutoFixture issue - it's an issue with Moq. You can reproduce the behavior from the "ThisDoesNotWork" (failing) test in the "ThisWorks" test. The "ThisWorks" test (which currently succeeds) can be made to fail in the same way by setting the Mock<T>.CallBase property to true:

mockTrigger.CallBase = true;

Likewise, the "ThisDoesNotWork" test can be made to pass by setting CallBase to false:

mockTrigger.CallBase = false;

The AutoMoqCustomization always sets CallBase to true because it gives a number of other surprising behaviors if CallBase is false, but it's not the default for Moq, and thus you see the difference in behavior.