2010-07-19 10 views
25

Ich versuche, eine Klasse aus dem Microsoft Sync Framework zu verspotten. Es hat nur einen internen Konstruktor. Wenn ich versuche, die folgenden:Verspottung eines Typs mit einem internen Konstruktor mit Moq

var fullEnumerationContextMock = new Mock<FullEnumerationContext>(); 

ich diesen Fehler:

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

Dies ist der 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.Mock 1.<InitializeInstance>b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock 1.InitializeInstance()

Wie kann ich mich um diese Arbeit?

+3

Vielen Dank für diese Frage! Es ist nur die Existenz, die mir geholfen hat. Ich war auf meinem eigenen Code in der Lage, den Konstruktor öffentlich zu machen. Leider kann mir das nicht helfen, aber du hast mir trotzdem geholfen +1 – Marcel

Antwort

17

Sie können keinen Typ vortäuschen, der keinen öffentlichen Konstruktor hat, da Moq ein Objekt dieses Typs nicht instanziieren kann. Je nachdem, was Sie testen wollen, haben Sie ein paar Optionen:

  1. Wenn ein Factory-Objekt ist oder eine andere Art und Weise von Instanzen FullEnumerationContext zu erhalten vielleicht können Sie verwenden, (sorry, ich bin nicht vertraut mit der sync framework)
  2. Sie könnten private Reflection verwenden, um einen FullEnumerationContext zu instanziieren, aber dann können Sie Methoden nicht vortäuschen.
  3. Sie könnten eine Schnittstelle und/oder ein Wrapper-Objekt einführen, das den Code, den Sie testen möchten, ansprechen könnte. Die Laufzeitimplementierung würde an den echten FullEnumerationContext delegieren, während Ihre Testzeitimplementierung die von Ihnen benötigte Aktion ausführen würde.
+3

Eigentlich können Sie den Mock für eine Klasse mit einem internen Konstruktor instanziieren. Sie benötigen nur das richtige InternalsVisibleTo-Attribut, das auf die Zielbaugruppe angewendet wird, wie unter "Erweiterte Funktionen" in https://code.google erläutert.com/p/moq/wiki/QuickStart – kzu

+11

@ kzu Das funktioniert nicht auf einer Drittanbieter-Bibliothek, da Sie die Bibliothek nicht selbst erstellen. – DBueno

3

Ich bin nicht wirklich ein Experte für Moq, aber ich denke, Sie müssen die Argumente für den Konstruktor angeben. In Rhino Mocks würden Sie sie wie folgt angeben:

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

Es ist wahrscheinlich in Moq ähnlich.

+1

Kann mir jemand bestätigen, dass das mit Moq möglich ist? Ich verwende Moq 3.1 – tjrobinson

+0

Nein. Das tut nicht. Castle verwendet den Standardkonstruktor für die Erstellung nach Klassen. Zumindest habe ich das hier gelesen [bei GitHub] (https://github.com/castleproject/Core/blob/c06adf27bf7a0dfe94529a2563aca94bdedd1cb0/src/Castle.Core/DynamicProxy/Generators/Emitter/AbstractTypeEmitter.cs#L323) – durilka

+3

Dies ist nur Wahr, wenn Sie etwas mit einem öffentlichen Nicht-Standardkonstruktor erstellen. Für einen internen Konstruktor (Standard oder sonst) haben Sie kein Glück. – RJFalconer

1

Basierend auf den Antworten von marcind ich eine Schnittstelle erstellt haben (IFullEnumerationContext), die ich spotten und dann habe ich zwei Überlastungen des Verfahrens habe ich zu testen, ich versuche, eine, die die FullEnumerationContext und eine andere nimmt, die nimmt IFullEnumerationContext. Es fühlt sich nicht gut an, aber es funktioniert. Bessere Vorschläge oder Verbesserungen wären willkommen.

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

Ich denke, es wäre besser, wenn die Überladung, die 'FullEnumerationContext' übernimmt, die Kontextinstanz in einen' FullEnumerationContextWrapper' umwandelt und diesen dann in die Überladung übergibt, die 'IFullEnumerationContext' akzeptiert. Auf diese Weise würde nur eine dieser Methoden den gesamten wichtigen Code enthalten. Die andere wäre eine einzeilige Anweisung, für die kein Komponententest erforderlich ist. – marcind

0

Eigentlich können Sie. Öffnen Sie Ihre AssemblyInfo.cs Datei und fügen Sie die folgende Zeile am Ende,

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

Verwandte Themen