Trying to mock MS OData client behaviour I'm getting strange errors which I haven't seen so far:
System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class.
----> System.TypeLoadException : VTable setup of type Castle.Proxies.ObjectProxy_3 failed
The error occurs when I'm setting up the mock expectations on generic interface method:
private Mock<IODataClient> _client;
[SetUp]
public void Setup()
{
_client = new Mock<IODataClient>();
// ...
}
[Test]
public async Task ShouldReturnFilteredBusinessPartners()
{
const string filter = "...";
var boundClient = SetupFindEntries("MyDataSet", new List<BusinessPartnerDto>());
// ...
}
private Mock<IBoundClient<TEntry>> SetupFindEntries<TEntry>(string entrySetName, IEnumerable<TEntry> result)
where TEntry : class
{
var boundClient = SetupBoundClient<TEntry>(entrySetName);
boundClient.Setup(mock => mock.FindEntriesAsync()).ReturnsAsync(result);
return boundClient;
}
private Mock<IBoundClient<TChangeRequest>> SetupBoundClient<TChangeRequest>(string entrySetName)
where TChangeRequest : class
{
var boundClient = new Mock<IBoundClient<TChangeRequest>>(MockBehavior.Strict);
// Here is the line where the exception occurs:
_client.Setup(mock => mock.For<TChangeRequest>(entrySetName))
.Returns(boundClient.Object);
return boundClient;
}
Both IBoundClient<T>and IODataClient are interfaces of course.
BusinessPartnerDto is a regular public POCO class with public properties (no private/protected/internal or static/const/readonly members, no inheritance).
Here is the full stack trace:
MyMd.Mobile.Core.UnitTests.Services.Data.MyMdServiceTests.ShouldReturnFilteredBusinessPartners
System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class.
----> System.TypeLoadException : VTable setup of type Castle.Proxies.ObjectProxy_3 failed
at Moq.Proxy.CastleProxyFactory.CreateProxy (System.Type mockType, Moq.Proxy.ICallInterceptor interceptor, System.Type[] interfaces, System.Object[] arguments) [0x00054] in C:\projects\moq4\Source\Proxy\CastleProxyFactory.cs:99
at Moq.Mock`1[T].<InitializeInstance>b__20_0 () [0x00068] in C:\projects\moq4\Source\Mock.Generic.cs:213
at Moq.PexProtector.Invoke (System.Action action) [0x00000] in C:\projects\moq4\Source\PexProtector.cs:56
at Moq.Mock`1[T].InitializeInstance () [0x00000] in C:\projects\moq4\Source\Mock.Generic.cs:191
at Moq.Mock`1[T].OnGetObject () [0x0000d] in C:\projects\moq4\Source\Mock.Generic.cs:245
at Moq.Mock.GetObject () [0x00000] in C:\projects\moq4\Source\Mock.cs:174
at Moq.Mock.get_Object () [0x00000] in C:\projects\moq4\Source\Mock.cs:169
at Moq.Mock`1[T].get_Object () [0x00000] in C:\projects\moq4\Source\Mock.Generic.cs:172
at MyMd.Mobile.Core.UnitTests.Services.Data.MyMdServiceTests.SetupBoundClient[TChangeRequest] (System.String entrySetName) [0x00015] in /Users/marekmierzwa/Repos/Abb.iMaster/MyMd.Mobile.Core.UnitTests/Services/Data/MyMdServiceTests.cs:188
at MyMd.Mobile.Core.UnitTests.Services.Data.MyMdServiceTests.SetupFindEntries[TEntry] (System.String entrySetName, System.Collections.Generic.IEnumerable`1[T] result) [0x00001] in /Users/marekmierzwa/Repos/Abb.iMaster/MyMd.Mobile.Core.UnitTests/Services/Data/MyMdServiceTests.cs:206
at MyMd.Mobile.Core.UnitTests.Services.Data.MyMdServiceTests+<ShouldReturnFilteredBusinessPartners>d__11.MoveNext () [0x00012] in /Users/marekmierzwa/Repos/Abb.iMaster/MyMd.Mobile.Core.UnitTests/Services/Data/MyMdServiceTests.cs:134
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /private/tmp/source-mono-d15-3/bockbuild-d15-3/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151
at NUnit.Framework.Internal.ExceptionHelper.Rethrow (System.Exception exception) [0x00006] in <d0c69b98d4da4342a70f9b139b717b6d>:0
at NUnit.Framework.Internal.AsyncInvocationRegion+AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete (System.Object invocationResult) [0x00030] in <d0c69b98d4da4342a70f9b139b717b6d>:0
at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod (NUnit.Framework.Internal.TestExecutionContext context) [0x00038] in <d0c69b98d4da4342a70f9b139b717b6d>:0
--TypeLoadException
at (wrapper managed-to-native) System.Reflection.MonoField:SetValueInternal (System.Reflection.FieldInfo,object,object)
at System.Reflection.MonoField.SetValue (System.Object obj, System.Object val, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Globalization.CultureInfo culture) [0x0008f] in /private/tmp/source-mono-d15-3/bockbuild-d15-3/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/corlib/System.Reflection/MonoField.cs:273
at System.Reflection.FieldInfo.SetValue (System.Object obj, System.Object value) [0x00000] in /private/tmp/source-mono-d15-3/bockbuild-d15-3/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/corlib/System.Reflection/FieldInfo.cs:142
at Castle.DynamicProxy.Internal.TypeUtil.SetStaticField (System.Type type, System.String fieldName, System.Reflection.BindingFlags additionalFlags, System.Object value) [0x00029] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.Generators.BaseProxyGenerator.InitializeStaticFields (System.Type builtType) [0x0000e] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateType (System.String name, System.Type[] interfaces, Castle.DynamicProxy.Generators.INamingScope namingScope) [0x0013d] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.Generators.ClassProxyGenerator+<>c__DisplayClass1_0.<GenerateCode>b__0 (System.String n, Castle.DynamicProxy.Generators.INamingScope s) [0x00000] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType (Castle.DynamicProxy.Generators.CacheKey cacheKey, System.Func`3[T1,T2,TResult] factory) [0x00127] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode (System.Type[] interfaces, Castle.DynamicProxy.ProxyGenerationOptions options) [0x00056] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType (System.Type classToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) [0x00026] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType (System.Type classToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) [0x00006] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy (System.Type classToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options, System.Object[] constructorArguments, Castle.DynamicProxy.IInterceptor[] interceptors) [0x00057] in <3a7700a4b99d46e49e2728ca3f076890>:0
at Moq.Proxy.CastleProxyFactory.CreateProxy (System.Type mockType, Moq.Proxy.ICallInterceptor interceptor, System.Type[] interfaces, System.Object[] arguments) [0x0002e] in C:\projects\moq4\Source\Proxy\CastleProxyFactory.cs:95
Both
IBoundClient<T>andIODataClientare interfaces of course.
Can you please either update the repro code above, such that these interfaces' definitions are shown as well, or mention what NuGet package or other external library they're defined in?
Sure - here is the NuGet package I'm using (version 4.28.0.0 for PCL projects).
Those particular interfaces can be found here:
IODataClient - https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Core/IODataClient.csIBoundClient - https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Core/Fluent/IBoundClient.csLet me know if you need anything else.
I do get an error, but not the one you reported. I'm using Moq 4.7.137 (which uses Castle Core 4.2.0).
System.ArgumentException: Type to mock must be an interface or an abstract or non-sealed class.
---> System.TypeLoadException: Method "NavigateTo" in type "Castle.Proxies.ObjectProxy" from assembly "DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" does not have an implementation.
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateType(String name, Type[] interfaces, INamingScope namingScope)
at Castle.DynamicProxy.Generators.ClassProxyGenerator.<>c__DisplayClass1_0.<GenerateCode>b__0(String n, INamingScope s)
at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options)
at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] intercep
tors)
at Moq.Proxy.CastleProxyFactory.CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, Object[] arguments) in C:\projects\moq4\Source\Proxy\CastleProxyFactory.cs:line 97.
--- ... ---
at Moq.Proxy.CastleProxyFactory.CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, Object[] arguments) in C:\projects\moq4\Source\Proxy\CastleProxyFactory.cs:line 101.
at Moq.Mock`1.<InitializeInstance>b__19_0() in C:\projects\moq4\Source\Mock.Generic.cs:line 218.
at Moq.PexProtector.Invoke(Action action) in C:\projects\moq4\Source\PexProtector.cs:line 56.
at Moq.Mock`1.InitializeInstance() in C:\projects\moq4\Source\Mock.Generic.cs:line 190.
at Moq.Mock`1.OnGetObject() in C:\projects\moq4\Source\Mock.Generic.cs:line 244.
at Moq.Mock`1.get_Object() in C:\projects\moq4\Source\Mock.Generic.cs:line 171.
at ConsoleApp.Program.SetupBoundClient[TChangeRequest](Mock`1 _client, String entrySetName) in …
which is likely the same issue as #469. (The ArgumentException can be ignored, it's the TypeLoadException that's relevant here.)
But I cannot reproduce your exact problem. Which version of Moq are you using? Can you think of anything else you may have omitted in your report?
Well, I'm also using the Moq version 4.7.137 with Castle.Core 4.2.0.
The unit test project is a regular .Net Framework 4.6 (console in order to run with nUnit Lite).
The tested project is PCL (44) but this should not mess with the mock setup.
Strange. If we don't have a reproduction, we can't really do anything about the error.
Would it be possible at all for you to start with your current code, then remove bits and pieces that aren't required to reproduce the problem you've observed, and keep removing more and more bits and pieces until you arrive at a minimal repro code that you could share here, as a ZIP file or similar?
Ok, I'll try doing what you propose.
One more thing that just came into my mind - the the tests are run on Mono 5.2.0 (on Mac). Maybe that's the difference.
@mmierzwa - I've been able to reproduce the error you've reported by running your code under Mono 5.2 on Windows.
This turns out to be a duplicate of #469: updating Moq's dependency on Castle Core to version 4.2.1 (see #482) resolves both issues.
A "hotfix" release of Moq (4.7.x) should be available in the next 20 hours or so, once you'll update Moq your issue should be resolved.
@mmierzwa: Moq 4.7.142 is now available. Once you update (which should automatically update its dependency Castle Core to 4.2.1), you should be good.
@stakx I just updated the package and confirm that everything works fine again.
Thank you for your time, especially for quick response, analysis and fix. I wish all OSS projects were managed this way.