简体   繁体   English

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

[英]Mocking a type with an internal constructor using Moq

I'm trying to mock a class from the Microsoft Sync Framework.我正在尝试从 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. System.NotSupportedException: Parent 没有默认构造函数。 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.Create 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[] 拦截器) Castle.DynamicProxy。 ProxyGenerator.Create ClassProxy(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() ClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] 拦截器) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, IInterceptor[] 拦截器) Moq.Mock 1.<InitializeInstance>b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock 1.InitializeInstance()

How can I work round this?我该如何解决这个问题?

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.您不能模拟没有公共构造函数的类型,因为 Moq 将无法实例化该类型的对象。 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)如果有工厂对象或其他获取 FullEnumerationContext 实例的方法,也许您可​​以使用它(抱歉,我不熟悉同步框架)
  2. You could use private reflection to instantiate a FullEnumerationContext, but then you would not be able to mock methods on it.您可以使用私有反射来实例化 FullEnumerationContext,但是您将无法在其上模拟方法。
  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.运行时实现将委托给真正的 FullEnumerationContext,而您的测试时实现将执行您需要的任何操作。

I am not really an expert on Moq, but I think you need to specify the arguments for the constructor.我不是真正的 Moq 专家,但我认为您需要为构造函数指定参数。 In Rhino Mocks you would specify them like this:在 Rhino Mocks 中,您可以像这样指定它们:

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

It is probably similar in Moq.在起订量中可能类似。

Actually you can.其实你可以。 Open your AssemblyInfo.cs file and add the following line at end,打开您的 AssemblyInfo.cs 文件并在末尾添加以下行,

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

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 .基于从答案marcind我创建了一个接口( IFullEnumerationContext ),我嘲笑,然后我有方法,我想的检验标准,采取的两个重载FullEnumerationContext ,另一个需要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);
}

In your System Under Test project you need:在您的被测系统项目中,您需要:

  • protected internal constructor visibility in your SUT class (eg FullEnumerationContext ) protected internal的 SUT 类中的protected internal构造函数可见性(例如FullEnumerationContext
  • AssemblyInfo.cs should expose their internals to the test project: AssemblyInfo.cs应该向测试项目公开它们的内部结构:

     [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM