2010-07-19 116 views
25

我試圖從Microsoft Sync Framework中嘲笑一個類。它只有一個內部構造函數。當我嘗試以下方法:使用Moq嘲笑使用內部構造函數的類型

var fullEnumerationContextMock = new Mock<FullEnumerationContext>(); 

我得到這個錯誤:

System.NotSupportedException: Parent does not have a default constructor. The default constructor must be explicitly defined.

這是堆棧跟蹤:

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()

我怎麼能圓這個工作嗎?

+3

感謝這個問題!這僅僅是存在幫助我。在我自己的代碼中,我能夠公開構造函數。不幸的是,這不能幫助你我的情況,但你仍然幫助我+1 – Marcel 2013-07-31 15:01:48

回答

17

你不能模擬一個沒有公共構造函數的類型,因爲Moq不能實例化該類型的對象。根據你想考什麼,你有幾種選擇:

  1. 如果有一個工廠對象或獲得FullEnumerationContext的情況下,也許你可以使用(對不起,我不熟悉的其他方式同步框架)
  2. 你可以使用私人反射來實例化一個FullEnumerationContext,但是你不能在它上面模擬方法。
  3. 您可以引入一個接口和/或包裝對象,它可以模擬被測代碼可以調用的對象。運行時實現將委託給真正的FullEnumerationContext,而您的測試時間實現將執行您需要的任何操作。
+3

其實你可以用一個內部構造函數實例化一個類的模擬。您只需要將適當的InternalsVisibleTo屬性應用於目標程序集,如https://code.google的「高級功能」中所述。com/p/moq/wiki/QuickStart – kzu 2013-04-03 17:28:26

+11

@kzu由於您不是自己構建庫,因此不適用於第三方庫。 – DBueno 2013-04-04 00:01:11

3

我不是Moq專家,但我認爲你需要指定構造函數的參數。在Rhino Mocks中,你可以這樣指定它們:

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

它可能類似於Moq。

+1

任何人都可以確認這是否可能與Moq?我正在使用Moq 3.1 – tjrobinson 2010-07-20 12:31:36

+0

不。 Castle使用默認構造函數進行逐類創建。至少這是我在這裏[在GitHub]上閱讀的內容(https://github.com/castleproject/Core/blob/c06adf27bf7a0dfe94529a2563aca94bdedd1cb0/src/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs#L323) – durilka 2013-04-08 14:00:32

+3

這只是如果你是一個公開的非默認構造函數的話,則返回true。對於內部構造函數(默認或其他),你的運氣不好。 – RJFalconer 2016-06-03 13:20:06

1

在此基礎上嘲笑我,然後我有方法,我想測試,一種採用了FullEnumerationContext的兩個重載我創建了一個接口(IFullEnumerationContext)從marcind的答案,另一個需要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); 
} 
+0

我認爲如果將FullEnumerationContext包裝在FullEnumerationContextWrapper中的上下文實例中,然後將其傳遞給接受IFullEnumerationContext的重載,那將會更好。這樣,只有其中一種方法會包含所有重要的代碼。另一個是單行聲明,它不需要進行單元測試。 – marcind 2010-07-20 18:50:27

0

其實你可以。打開AssemblyInfo.cs文件,並在末尾添加以下行,

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]