35

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.Mock1.<InitializeInstance>b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock1.InitializeInstance()

How can I work round this?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Tom Robinson
  • 8,348
  • 9
  • 58
  • 102
  • 4
    Thanks for this question! It's mere existence helped me out. I was, on my own code, able to make the constructor public. Unfortunately this can not help i your case, but you still helped me out +1 – Marcel Jul 31 '13 at 15:01

5 Answers5

24

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:

  1. 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)
  2. You could use private reflection to instantiate a FullEnumerationContext, but then you would not be able to mock methods on it.
  3. 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.
marcind
  • 52,944
  • 13
  • 125
  • 111
  • 4
    Actually you CAN instantiate the mock for a class with an internal constructor. You just need the proper InternalsVisibleTo attribute applied to the target assembly, as explained in "Advanced Features" in https://code.google.com/p/moq/wiki/QuickStart – kzu Apr 03 '13 at 17:28
  • 21
    @kzu That won't work on a third party library since you are not building the library yourself. – DBueno Apr 04 '13 at 00:01
4

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.

Grzenio
  • 35,875
  • 47
  • 158
  • 240
  • 2
    Can anyone confirm if this is possible with Moq? I'm using Moq 3.1 – Tom Robinson Jul 20 '10 at 12:31
  • No. That doesn't. Castle uses default constructor for class-by-type creation. At least that's what I read here [at GitHub](https://github.com/castleproject/Core/blob/c06adf27bf7a0dfe94529a2563aca94bdedd1cb0/src/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs#L323) – durilka Apr 08 '13 at 14:00
  • 4
    This is only true if you're Moqing something with a public non-default constructor. For an internal constructor (default or otherwise) you're out of luck. – RJFalconer Jun 03 '16 at 13:20
4

Actually you can. Open your AssemblyInfo.cs file and add the following line at end,

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

fhnaseer
  • 7,159
  • 16
  • 60
  • 112
2

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);
}
Community
  • 1
  • 1
Tom Robinson
  • 8,348
  • 9
  • 58
  • 102
  • I think it would be better if the overload that takes `FullEnumerationContext` wrapped the context instance in a `FullEnumerationContextWrapper` and then passed that into the overload that accepts `IFullEnumerationContext`. That way only one of these methods would contain all the important code. The other one would be a one-line statement that does not need to have a unit test associated with it. – marcind Jul 20 '10 at 18:50
2

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")]
    
Mariano Desanze
  • 7,847
  • 7
  • 46
  • 67