使用Moq模拟具有内部构造函数的类型

我正在尝试从Microsoft Sync Framework模拟一个类。 它只有一个内部构造函数。 当我尝试以下内容时:

var fullEnumerationContextMock = new Mock(); 

我收到此错误:

System.NotSupportedException:Parent没有默认构造函数。 必须显式定义默认构造函数。

这是堆栈跟踪:

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.Create ClassProxy(类型classToProxy,Type [] additionalInterfacesToProxy,ProxyGenerationOptions选项,IInterceptor []拦截器)Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(类型classToProxy,Type [] additionalInterfacesToProxy,IInterceptor []拦截器)Moq.Mock 1.b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock 1.InitializeInstance()

我该如何解决这个问题呢?

您不能模拟没有公共构造函数的类型,因为Moq将无法实例化该类型的对象。 根据您要测试的内容,您有以下几种选择:

  1. 如果有工厂对象或其他获取FullEnumerationContext实例的方式,也许你可以使用它(对不起,我不熟悉同步框架)
  2. 您可以使用私有reflection来实例化FullEnumerationContext,但是您将无法在其上模拟方法。
  3. 您可以引入一个接口和/或包装器对象,它可以模拟被测试的代码可以调用。 运行时实现将委托给真正的FullEnumerationContext,而您的测试时实现将执行您需要的任何操作。

我不是Moq的专家,但我认为你需要指定构造函数的参数。 在Rhino Mocks中,您可以像这样指定它们:

 var fullEnumerationContextMock = new Mock(arg1, arg2); 

它在Moq中可能类似。

基于marcind的答案我创建了一个接口( IFullEnumerationContext ),我模拟然后我有两个重载我试图测试的方法,一个采用IFullEnumerationContext ,另一个采用IFullEnumerationContext 。 它感觉不太好,但确实有效。 任何更好的建议或改进都将受到欢迎。

 public override void EnumerateItems(FullEnumerationContext context) { List listItemFieldDictionary = EnumerateItemsCommon(); context.ReportItems(listItemFieldDictionary); } public void EnumerateItems(IFullEnumerationContext context) { List listItemFieldDictionary = EnumerateItemsCommon(); context.ReportItems(listItemFieldDictionary); } 

其实你可以。 打开AssemblyInfo.cs文件并在结尾添加以下行,

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]