2010-03-05 14 views
20

Ist es richtig, dass Rhino Mocks Stubs und Mocks nur für Interfaces geeignet sind, nicht für konkrete Klassen? Ich habe ziemlich viel Zeit damit verbracht, dieses Code-Stück zum Laufen zu bringen. Ich habe nicht erwartet, dass der stubbed pubSubClient die Send-Methode immer von der Klasse aufruft. Diese Methode hat einige Abhängigkeiten und löst eine Ausnahme aus.Rhino Mocks Stubs und Mocks sind nur gut für Schnittstellen?

[Test] 
public void Test01() 
{ 
    PubSubMessage psm = new PubSubMessage(); 
    var pubSubClient = MockRepository.GenerateStub<PubSubClient>(); 
    pubSubClient.Stub(x => x.Send(psm)).IgnoreArguments().Return(null); 
    // actual PubSubClient Send method throws exception 
    // the rest of the test is skipped... 
} 

Allerdings, wenn ich die Schnittstelle extrahiert haben und den gleichen Test mit IPubSubClient laufen, so scheint es wie erwartet zu arbeiten.

Bedeutet es, dass ich die Schnittstelle für jede Klasse extrahieren muss, die ich mit Rhino spotten will? Oder ich vermisse etwas, technisch oder konzeptionell?

UPDATE: OK, es scheint, dass ich herausgefunden, was Teil I fehlte: Rhino Mocks können nicht abfangen Anrufe an nicht-virtuellen Methoden. Also, ich denke ich benutze entweder Schnittstellen oder mache jede Methode auf der konkreten Klasse virtuell. Bitte korrigieren Sie mich, wenn es eine andere Option gibt.

Antwort

23

Bryan's Antwort der Verwendung von partiellen Mocks ist falsch. Das ist nicht, wozu teilweise Mocks sind.

Die Antwort von Jon Erickson ist größtenteils korrekt: Rhino Mocks und Moq können nicht-virtuelle Aufrufe weder abfangen noch statische Methoden oder Eigenschaften abfangen. Das bedeutet, dass Sie folgendes nicht fälschen können:

DateTime.Now; // static property, can't fake static property 
someClass.SomeNonVirtualMethod(); // can't fake non-virtual method 
sealedClass.Foo(); // can't fake anything on sealed classes 
Utilities.SomeStaticMethod(); // can't fake static methods 
someList.Any(); // can't fake extension methods like Linq's .Any() 

TypeMock kann diese fälschen, wie Jon erwähnte.

Es sollte beachtet werden, gibt es eine zusätzliche Spott Framework, die alle Anrufe abfangen kann: die Microsoft Moles framework. Es funktioniert genauso wie TypeMock, es verwendet die .NET Profiler-API zum Abfangen von Anrufen.

Moles ist frei (für jetzt). Es ist auch Beta. Moles funktioniert nur mit Microsoft Pex tools. Und seine API ist der raffinierten, eleganten API von TypeMock deutlich unterlegen.

+4

Wenn Sie angeben, dass partielle Mocks nicht für etwas sind, ist es hilfreicher zu sagen, wofür sie in Ihrer Antwort sind. Partielle Mocks sollen nur einen Teil einer Klasse vortäuschen, das macht sie nützlich (und erforderlich), um eine abstrakte Klasse zu verspotten, in der ein normaler Spott nicht damit umgehen kann. Dies ermöglicht das Testen von abstrakten Methoden. Ein partieller Mock (zumindest in Rhino) verspottet jede Klasse und ist nicht auf abstrakte Klassen beschränkt. Beachten Sie jedoch, ob es einen Implementierungscode gibt, der bei der Rückgabe aufgerufen wird. –

+0

(Nekro-Alarm): Ich habe gerade herausgefunden, dass deine Klasse nicht einmal abstrakt sein muss, um Methoden virtuell zu machen! So eine kleine Sache, aber ich habe es nie zuvor in Betracht gezogen :-) – Heliac

1

Partielle Mocks ermöglichen es Ihnen, die Funktionalität einer konkreten Klasse zu überspielen. Siehe: http://www.ayende.com/wiki/Rhino+Mocks+Partial+Mocks.ashx

+0

Ich fürchte, teilweise Mocks tun das nicht ganz. Sie sind hilfreich, um einige nicht implementierte Methoden in abstrakten Klassen zu verspotten, aber wenn es eine Implementierung gibt, wird sie immer noch aufgerufen. Mit anderen Worten, in meinem Beispiel ändert das Ersetzen von MockRepository.GenerateStub () durch MockRepository.GeneratePartialMock () nichts. –

+1

machen Sie Ihre Methode virtuell. –

3

Sie müssen die Methoden virtuell machen. Rhino-Mocks (und die meisten anderen Isolations-Frameworks) verwenden Proxy-Klassen, um die Stubs/Mocks zu erstellen.

Wenn Sie TypeMock Trenner verwenden, können Sie etwas verspotten, weil diese Isolation Framework .NET Profiler API nutzt, um seine Stubs zu erstellen/spottet

+0

+1. Wie das OP in seinem Update erwähnt, müssen die Methoden virtuell sein. Dies gilt auch für Moq und (glaube ich) für jedes .NET-Isolationsframework mit Ausnahme von TypeMock Isolator. Die billige und einfache Lösung besteht darin, die Methoden virtuell zu machen (oder eine Schnittstelle zu extrahieren). – TrueWill

0

Ich glaube nicht, es gibt einen anderen Weg, um dieses andere zu tun, als zu machen Alle Methoden, die Sie virtuell vortäuschen wollen - Ich glaube, die Art, wie Mocks von konkreten Klassen erzeugt werden, besteht darin, die betonierte Klasse dynamisch zu klassifizieren und dann die angegebenen Methoden mit dem im Test angegebenen Verhalten zu überschreiben, was eine virtuelle Methode erfordert richtig funktionieren.

2

Das ist im Wesentlichen richtig und ist im Allgemeinen gute Praxis. Es ist jedoch nur nützlich für eine bestimmte Art der Codierung.

Denken Sie nicht an Objekte als Dinge, die eine 'höhere Macht' manipulieren kann. Betrachten Sie sie stattdessen als autonome "Menschen", die einander Botschaften senden können. Eine Schnittstelle repräsentiert die Nachrichten, die von einem einzelnen Objekt gesendet werden.

Anschließend verwenden Sie Mocks, um zu überprüfen, ob die richtigen Nachrichten gesendet wurden, und nicht, um gefälschte Implementierungen von Abhängigkeiten bereitzustellen.

Im Idealfall erstellen Sie keine Schnittstelle, die genau einer vorhandenen Klasse entspricht - stattdessen die Klasse , die verbraucht die Schnittstelle erklärt ihre Bedürfnisse in Form einer Schnittstelle.