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

时间:2010-07-19 08:17:44

标签: c# unit-testing moq microsoft-sync-framework

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

var fullEnumerationContextMock = new Mock<FullEnumerationContext>();

我收到此错误:

  

System.NotSupportedException:Parent   没有默认构造函数。   默认构造函数必须是   明确定义。

这是堆栈跟踪:

  

System.Reflection.Emit.TypeBuilder.DefineDefaultConstructorNoLock(MethodAttributes   属性)       System.Reflection.Emit.TypeBuilder.DefineDefaultConstructor(MethodAttributes   属性)       System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()       System.Reflection.Emit.TypeBuilder.CreateType()       Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()       Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(类型[]   接口,ProxyGenerationOptions选项)       Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxy(类型classToProxy,Type [] additionalInterfacesToProxy,   ProxyGenerationOptions选项)       Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy,Type [] additionalInterfacesToProxy,   ProxyGenerationOptions选项)       Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(类型classToProxy,Type [] additionalInterfacesToProxy,   ProxyGenerationOptions选项,Object [] constructorArguments,   IInterceptor []拦截器)       Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(类型classToProxy,Type [] additionalInterfacesToProxy,   ProxyGenerationOptions选项,IInterceptor []拦截器)       Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(类型classToProxy,Type [] additionalInterfacesToProxy,IInterceptor []   拦截器)       Moq.Mock 1.<InitializeInstance>b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock 1.InitializeInstance()

我该如何解决这个问题?

5 个答案:

答案 0 :(得分:20)

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

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

答案 1 :(得分:4)

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

var fullEnumerationContextMock = new Mock<FullEnumerationContext>(arg1, arg2);

在Moq中可能类似。

答案 2 :(得分:2)

基于marcind的答案,我创建了一个界面(IFullEnumerationContext),我嘲笑然后我有两个重载我试图测试的方法,一个接受FullEnumerationContext和另一个IFullEnumerationContext。它感觉不太好,但确实有效。欢迎任何更好的建议或改进。

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);
}

答案 3 :(得分:1)

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

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

答案 4 :(得分:0)

在“被测系统”项目中,您需要:

  • protected internal在SUT类中的构造函数可见性(例如FullEnumerationContext
  • AssemblyInfo.cs应该向测试项目公开其内部信息:

    [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]