Ich arbeite an .NET 4.0 mit C # in Windows 7.
Ich möchte die Kommunikation zwischen einigen Methoden mit Mock testen. Das einzige Problem ist, dass ich es ohne Implementierung einer Schnittstelle tun möchte. Ist das möglich?
Ich habe gerade viele Themen und einige Tutorials über Scheinobjekte gelesen, aber alle haben Schnittstellen verspottet und nicht die Klassen. Ich habe versucht, Rhino und Moq Frameworks zu verwenden.
Antworten:
Markieren Sie einfach jede Methode, die Sie fälschen müssen, als
virtual
(und nicht als privat). Dann können Sie eine Fälschung erstellen, die die Methode überschreiben kann.Wenn Sie
new Mock<Type>
einen parameterlosen Konstruktor verwenden und keinen haben, können Sie die Parameter als Argumente des obigen Aufrufs übergeben, da er einen Typ von benötigtparam Objects
quelle
Die meisten Verspottungs-Frameworks (einschließlich Moq und RhinoMocks) generieren Proxy-Klassen als Ersatz für Ihre verspottete Klasse und überschreiben die virtuellen Methoden mit dem von Ihnen definierten Verhalten. Aus diesem Grund können Sie nur Schnittstellen oder virtuelle Methoden für konkrete oder abstrakte Klassen verspotten. Wenn Sie eine konkrete Klasse verspotten, müssen Sie außerdem fast immer einen parameterlosen Konstruktor bereitstellen, damit das Verspottungsframework weiß, wie die Klasse instanziiert wird.
Warum die Abneigung gegen das Erstellen von Schnittstellen in Ihrem Code?
quelle
Mit MoQ können Sie konkrete Klassen verspotten:
var mocked = new Mock<MyConcreteClass>();
Auf diese Weise können Sie jedoch
virtual
Code (Methoden und Eigenschaften) überschreiben .quelle
new Mock<MyConcreteClass>(param1, anotherParam, thirdParam, evenMoreParams);
Ich denke, es ist besser, eine Schnittstelle für diese Klasse zu erstellen. Und erstellen Sie einen Komponententest über die Schnittstelle.
Wenn Sie keinen Zugriff auf diese Klasse haben, können Sie einen Adapter für diese Klasse erstellen.
Zum Beispiel:
public class RealClass { int DoSomething(string input) { // real implementation here } } public interface IRealClassAdapter { int DoSomething(string input); } public class RealClassAdapter : IRealClassAdapter { readonly RealClass _realClass; public RealClassAdapter() => _realClass = new RealClass(); int DoSomething(string input) => _realClass.DoSomething(input); }
Auf diese Weise können Sie mit IRealClassAdapter ganz einfach ein Modell für Ihre Klasse erstellen.
Hoffe, es funktioniert.
quelle
Die Standard-Mocking-Frameworks erstellen Proxy-Klassen. Dies ist der Grund, warum sie technisch auf Schnittstellen und virtuelle Methoden beschränkt sind.
Wenn Sie auch "normale" Methoden verspotten möchten, benötigen Sie ein Tool, das mit Instrumentierung anstelle der Proxy-Generierung arbeitet. Zum Beispiel können MS Moles und Typemock das. Aber der erstere hat eine schreckliche "API", und der letztere ist kommerziell.
quelle
Wenn Sie die zu testende Klasse nicht ändern können, kann ich nur die Verwendung von MS Fakes https://msdn.microsoft.com/en-us/library/hh549175.aspx vorschlagen . MS Fakes funktioniert jedoch nur in einigen Editionen von Visual Studio.
quelle
Wenn es immer schlimmer wird, können Sie ein Schnittstellen- und Adapterpaar erstellen. Sie würden alle Verwendungen von ConcreteClass ändern, um stattdessen die Schnittstelle zu verwenden, und im Produktionscode immer den Adapter anstelle der konkreten Klasse übergeben.
Der Adapter implementiert die Schnittstelle, sodass der Mock auch die Schnittstelle implementieren kann.
Es ist mehr Gerüst als nur eine Methode virtuell zu machen oder nur eine Schnittstelle hinzuzufügen, aber wenn Sie keinen Zugriff auf die Quelle für die konkrete Klasse haben, können Sie aus einer Bindung herauskommen.
quelle
Ich habe so etwas in einem der alten und älteren Projekte gesehen, in denen ich gearbeitet habe, die keine Schnittstellen oder Best Practices enthalten, und es ist auch zu schwierig, sie zu erzwingen, Dinge neu zu erstellen oder den Code aufgrund der Reife des Projektgeschäfts umzugestalten In meinem UnitTest-Projekt habe ich einen Wrapper über die Klassen erstellt, die ich verspotten möchte, und die Wrapper-Implementierungsschnittstelle, die alle meine benötigten Methoden enthält, die ich einrichten und mit denen ich arbeiten möchte. Jetzt kann ich den Wrapper anstelle der realen Klasse verspotten.
Zum Beispiel:
Zu testender Dienst, der keine virtuellen Methoden oder Implementierungsschnittstellen enthält
public class ServiceA{ public void A(){} public String B(){} }
Wrapper zu moq
public class ServiceAWrapper : IServiceAWrapper{ public void A(){} public String B(){} }
Die Wrapper-Schnittstelle
public interface IServiceAWrapper{ void A(); String B(); }
Im Unit-Test können Sie nun den Wrapper verspotten:
public void A_Run_ChangeStateOfX() { var moq = new Mock<IServiceAWrapper>(); moq.Setup(...); }
Dies ist möglicherweise nicht die beste Vorgehensweise, aber wenn Ihre Projektregeln Sie auf diese Weise zwingen, tun Sie es. Fügen Sie außerdem alle Ihre Wrapper in Ihr Unit-Test-Projekt oder Helper-Projekt ein, das nur für die Unit-Tests angegeben wurde, um das Projekt nicht mit nicht benötigten Wrappern oder Adaptern zu überladen.
Update: Diese Antwort stammt aus mehr als einem Jahr, aber in diesem Jahr habe ich viele ähnliche Szenarien mit unterschiedlichen Lösungen gesehen. Zum Beispiel ist es so einfach, mit Microsoft Fake Framework Mocks, Fakes und Stubs zu erstellen und sogar private und geschützte Methoden ohne Schnittstellen zu testen. Sie können lesen: https://docs.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2017
quelle