问题
I'm trying to mock a class from the Microsoft Sync Framework. It only has an internal constructor. When I try the following:
var fullEnumerationContextMock = new Mock<FullEnumerationContext>();
I get this error:
System.NotSupportedException: Parent does not have a default constructor. The default constructor must be explicitly defined.
This is the stack trace:
System.Reflection.Emit.TypeBuilder.DefineDefaultConstructorNoLock(MethodAttributes attributes) System.Reflection.Emit.TypeBuilder.DefineDefaultConstructor(MethodAttributes attributes) System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() System.Reflection.Emit.TypeBuilder.CreateType() Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType() Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options) Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, IInterceptor[] interceptors) Moq.Mock
1.<InitializeInstance>b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock
1.InitializeInstance()
How can I work round this?
回答1:
You cannot mock a type that does not have a public constructor because Moq will not be able to instantiate an object of that type. Depending on what you are trying to test, you have a few options:
- If there's a factory object or some other way of obtaining instances of FullEnumerationContext perhaps you can use that (sorry, I'm not familiar with the sync framework)
- You could use private reflection to instantiate a FullEnumerationContext, but then you would not be able to mock methods on it.
- You could introduce an interface and/or wrapper object that's mockable that the code under test could invoke. The runtime implementation would delegate to the real FullEnumerationContext, while your test-time implementation would perform whatever action you need.
回答2:
I am not really an expert on Moq, but I think you need to specify the arguments for the constructor. In Rhino Mocks you would specify them like this:
var fullEnumerationContextMock = new Mock<FullEnumerationContext>(arg1, arg2);
It is probably similar in Moq.
回答3:
Based on the answers from marcind I've created an interface (IFullEnumerationContext
) which I mock and then I've got two overloads of the method I am trying to test, one that takes the FullEnumerationContext
and another that takes IFullEnumerationContext
. It doesn't feel great, but it does work. Any better suggestions or improvements would be welcome.
public override void EnumerateItems(FullEnumerationContext context)
{
List<ItemFieldDictionary> listItemFieldDictionary = EnumerateItemsCommon();
context.ReportItems(listItemFieldDictionary);
}
public void EnumerateItems(IFullEnumerationContext context)
{
List<ItemFieldDictionary> listItemFieldDictionary = EnumerateItemsCommon();
context.ReportItems(listItemFieldDictionary);
}
回答4:
Actually you can. Open your AssemblyInfo.cs file and add the following line at end,
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
回答5:
In your System Under Test project you need:
protected internal
constructor visibility in your SUT class (e.g.FullEnumerationContext
)AssemblyInfo.cs
should expose their internals to the test project:[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
来源:https://stackoverflow.com/questions/3279412/mocking-a-type-with-an-internal-constructor-using-moq