Description
Describe the Bug
Given an internal class DerivedControl
inheriting from System.Windows.Forms.Control
, constructing new Mock<DerivedControl>().Object
throws ArgumentException
, wrapping TypeLoadException
. I cannot reproduce this issue without using System.WIndows.Forms.Control
.
I am not certain if this is a bug in Castle.Core, but thought I would ask here first.
Steps to Reproduce
Full code with additional examples can be found at https://github.com/andrewimcclement/MoqInternalsVisibleToIssue.
This test (in Production.Tests.csproj
) passes on .NET Framework 4.8 but fails on .NET 6.0 & .NET 8.0.
using NUnit.Framework;
using Moq;
namespace Production.Tests;
public class DerivedControl : Control {}
internal class InternalsVisibleToTests
{
[Test]
public void FailsOnNetCore()
{
var obj = new Mock<DerivedControl>();
Assert.That(() => obj.Object, Throws.Nothing);
}
}
Expected Behavior
Given this passes on .NET Framework 4.8, I would expect this to pass (or understand why System.Windows.Forms.Control is special
Exception with Stack Trace
.NET 8.0 stack trace: (.NET 6.0 stack trace is similar)
System.ArgumentException : Type to mock (Production.InternalDerivedControl) must be an interface, a delegate, or a non-sealed, non-static class.
----> System.TypeLoadException : Method 'NotifyValidationResult' on type 'Castle.Proxies.InternalDerivedControlProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is overriding a method that is not visible from that assembly.
at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) in /_/src/Moq/Interception/CastleProxyFactory.cs:line 114
at Moq.Mock`1.InitializeInstance() in /_/src/Moq/Mock`1.cs:line 502
at Moq.Mock`1.OnGetObject() in /_/src/Moq/Mock`1.cs:line 516
at Moq.Mock.get_Object() in /_/src/Moq/Mock.cs:line 180
at Moq.Mock`1.get_Object() in /_/src/Moq/Mock`1.cs:line 453
at Production.Tests.InternalsVisibleToTests.FailsOnNetCore() in C:\Git\github\andrewimcclement\MoqInternalsVisibleToIssue\Production.Tests\UnitTest1.cs:line 21
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
--TypeLoadException
at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeInfoImpl()
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.BaseClassProxyGenerator.GenerateType(String name, INamingScope namingScope)
at Castle.DynamicProxy.Generators.BaseProxyGenerator.<>c__DisplayClass13_0.<GetProxyType>b__0(CacheKey cacheKey)
at Castle.Core.Internal.SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Castle.DynamicProxy.Generators.BaseProxyGenerator.GetProxyType()
at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) in /_/src/Moq/Interception/CastleProxyFactory.cs:line 110
Note that InternalDerivedControl is a non-sealed, non-static class, so even if this behaviour is correct, the error message seems inaccurate.
Also, looking at the source code of System.Windows.Forms.Control
, I cannot see any relevant change to internal virtual void NotifyValidationResult
Version Info
Moq 4.20.70 used (implicitly using Castle.Core 5.1.1).
Additional information
I hit this issue while trying to upgrade some test projects from .NET Framework to .NET 8.