beim Schreiben von meinen UnitTests ersetze ich externe Abhängigkeiten der
zu testenden Klasse durch ein Objekt, welches über die identische
Schnittstelle wie die externe Abhängigkeit verfügt und spritze dieses aus
meiner Testklasse von aussen ein.
Bei der Benennung solcher "Ersetzungsobjekte" bin ich mir nicht sicher, ob
ich den Begriff "Mock" oder "Stub" verwenden soll.
Worin sollen sich ein "Stub" von einem "Mock" unterscheiden?
Grüße
Christian
> Worin sollen sich ein "Stub" von einem "Mock" unterscheiden?
*Vorab*
Die zu testende Komponente nennt man in der Fachsprache auch System
Under Test (SUT). Ein SUT steht normal nicht allein. Dazu erfolgt
gängigerweise eine Interaktion des SUT mit seiner Umwelt über
Schnittstellen. Jetzt kommen Mock- oder Stub-Objekte ins Spiel. Beide
simulieren die Interaktion des SUT mit den realen externen
Komponenten.
*Stubs* (aus dem engl.: Stummel, Stumpf) werden oft mit Proxy-Begriff
gleichgesetzt. Also im Deutschen etwa Stellvertreter, also Code, der
stellvertretend für den realen Code steht. Stub-Code ist zum Beispiel
noch nicht entwickelt, zu kompliziert für den Test oder auf einem
Remote-Rechner oder Remote-Memory. Ein Stub liefert keine Echtdaten,
sondern nur vorkonfigurierte, zum Kontext passende Daten.
*Mock* Objekte (aus dem engl. Fälschung) sind quasi gefälschte
Objekte. Mock-Objekte implementieren die Schnittstelle, über die das
zu testende Objekt auf seine Umgebung zugreift. Im Gegensatz zu Stub-
Objekten, die "nur" stellvertretend für realen Code stehen oder nur
vorbereitete Daten auf Anfrage liefern, verifiziert ein Mock auch das
Verhalten des SUT. Insbesondere stellt es sicher, dass die erwarteten
Methodenaufrufe vollständig, mit den korrekten Parametern und in der
erwarteten Reihenfolge durchgeführt werden. Genau wie ein Stub-Objekt
liefert ein Mock-Objekt keine Echtdaten, sondern nur zum Testfall
passende, vorher festgelegte Werte.
Oft ist die Anwendung von "Mocking-Framework's" sinnvoll, um die
wiederkehrenden Aufgaben bei Unit-Tests zu vereinfachen:
[HowTo: UnitTests und Einführung in Mocking mit Rhino.Mocks | Code-
Inside Blog]
http://code-inside.de/blog/2008/08/05/howto-unittests-und-einfhrung-in-mocking-mit-rhinomocks/
[moq - Project Hosting on Google Code]
http://code.google.com/p/moq/
[Unit testing .NET-Unit Test C# or VB.NET -Typemock -]
http://learn.typemock.com/
(etc. ...)
________
[Mocks Aren't Stubs]
http://martinfowler.com/articles/mocksArentStubs.html
[inside-scrum: Stub vs. Mock]
http://inside-scrum.blogspot.com/2007/07/stub-vs-mock.html
[Mock-Objekt – Wikipedia]
http://de.wikipedia.org/wiki/Mock-Objekt
[Stub (Programmierung) – Wikipedia]
http://de.wikipedia.org/wiki/Stub_(Programmierung)
ciao Frank
--
Dipl.Inf. Frank Dzaebel [MCP/MVP C#]
http://Dzaebel.NET
Gar nicht.
Genauer: das kannst nur du sagen, denn Mocks und Stubs unterscheiden
sich ausschließlich in deiner Intention; es gibt keinerlei
intrinsische Unterschiede.
Der Unterschied zwischen einem Mock und einem Stub besteht lediglich
darin, wie du ihn benutzt, nichts weiter.
Der Unterschied ist hauptsächlich deine Verifikations-Philosophie:
siehst du einen Test eher als Verifikation des End-Zustandes oder als
Verifikation der Interaktion?
Der Begriff des Stubs stammt aus der Zustandsverifikation. Man führt
die Aktion aus und vergleicht dann den tatsächlichen End-Zustand
(Ist-Zustand) des Systems mit einem vorher definierten Soll-Zustand.
Stubs dienen dazu, in Modul-Tests das zu testende Modul zu isolieren
bzw. in funktionalen Tests unkontrollierbare externe Abhängigkeiten zu
eliminieren. Eine signifikante Eigenschaft von Stubs ist, dass sie
kein nennenswertes Verhalten haben, sondern lediglich vorbereitete
Werte zurückgeben.
Der Begriff des Mocks stammt aus dem Interaktionsverifikation. Beim
Man führt die Aktion aus und zeichnet die Interaktionen zwischen den
Akteuren (im Falle von C# also die Methodenaufrufe zwischen den
Objekten) auf. Diese Aufzeichnung vergleicht man dann mit der
erwarteten "Choreographie" (Interaktions-Sequenz). Mocks sind
diejenigen Objekte, die für die Aufzeichnung verantwortlich sind. Eine
signifikante Eigenschaft von Mocks ist, dass sie Erwartungen
(Expectations) haben, welche ihrer Methoden wie oft in welcher
Reihenfolge mit welchen Argumenten aufgerufen werden.
Zustandsverifikation ist also eher statisch und eher Black-Box während
Interaktionsverifikation eher dynamisch und eher White-Box ist. Bei
der Zustandsverifikation sage ich "Los!" und dann halte ich mir die
Augen zu während das Programm losrödelt und irgendetwas macht, was
mich nicht die Bohne interessiert. Erst ganz am Ende schaue ich auf
das Ergebnis. Bei der Interaktionsverifikation dagegen ist das
eigentliche Ergebnis gar nicht so wichtig, dafür schaue ich dem
Programm ganz genau auf die Finger, ob es auch jede Bewegung richtig
macht.
Ein zweiter Unterschied zwischen Mocks und Stubs zeigt sich beim
Testgetriebenen Entwickeln. Hier gibt es zwei Lager: die Klassizisten
und die Mockisten. Die Klassizisten verwenden Zustandsverifikation und
versuchen, so weit als möglich das reale Objekt zu verwenden und Stubs
nur, wenn es *unbedingt* nötig ist. Mockisten verwenden
Interaktionsverifikation und versuchen, so weit als möglich
*sämtliche* Kollaborateure durch Mocks zu ersetzen und
*ausschließlich* für das Modul-unter-Test das reale Objekt.
Mockistisches TDD tendiert dazu, geringer verkuppelten Produktionscode
zu produzieren, während der Testcode stärker mit dem Produktionscode
verkuppelt ist. Ersteres liegt daran, dass starke Verkupplung zu
komplizierten Tests mit vielen Mocks führt und daher vermieden wird,
letzteres liegt daran, dass die internen Interaktionen zwischen den
Objekten teil des Tests sind und der Test daher sensibel auf interne
Refaktorierung des Produktionscode reagiert.
In Wirklichkeit ist es so, dass so ziemlich jede nicht-triviale
interaktionsverifizierende Testsuite Mocks enthält, welche auch
vorbereitete Werte zurückgeben (mithin Merkmale eines Stubs aufweisen)
und jede nicht-triviale zustandsverifizierende Testsuite Stubs
enthält, welche Methodenaufrufe verifizieren (mithin als Mocks
agieren). Zudem enthält fast jedes nicht-triviale Projekt sowohl
interaktionsverifizierende als auch zustandsverifizierende Tests, wenn
nicht sogar Tests, die beide Philosophien in sich vereinen.
Mit Mocks und Stubs ist das so ähnlich wie mit Karneval und Fasching,
Manta und Golf, HSV und St. Pauli, Kölsch und Alt: die beiden sind
eigentlich dasselbe, unterscheiden sich allerhöchstens in irrelevanten
oder imaginären Details; diese Details jedoch werden von einer
fanatisch-religiösen Minderheit der Anhänger beider Bewegungen
vollkommen überhöht und zur Basis eines Feldzuges gemacht.
Mocks und Stubs zählen zusammen mit ihren anderen drei Kollegen, den
Dummies, Fakes und Spies (Spionen) zu den sogenannten "Test Doubles"
(in Anlehnung an den Begriff des "Doubles" in der Filmindustrie) und
die Unterschiede zwischen diesen sind so marginal, dass viele moderne
Double-Frameworks (z.B. RR) gar nicht mehr zwischen ihnen
unterscheiden.
(Nur der Vollständigkeit halber: ein Dummy hat keinerlei Funktion,
außer den Test überhaupt zum Laufen/Compilieren zu bringen. Beispiel:
wir wollen den Fehlerfall einer TryParse-Methode testen: der Compiler
zwingt uns, ein out-Argument zu übergeben, obwohl wir genau wissen,
dass es nie benutzt werden wird, weil wir ja den Fehlerfall testen.
Ein Fake ist wie ein Stub, außer dass er ein eigenständiges Verhalten
hat und nicht nur vorbereitete Werte zurückliefert. Beispiel: eine
In-Memory-SQLite-Datenbank als Double für einen SQL Server. Und ein
Spy ist ähnlich einem Mock, außer dass er das korrekte Verhalten des
Zielobjektes tatsächlich implementiert. Während also ein Mock die
Methodenaufrufe aufzeichnet *anstatt* die eigentliche Aktion des
tatsächlichen Zielobjektes auszuführen, führt ein Spy diese Funktion
aus und zeichnet *zusätzlich* noch die Methodenaufrufe auf.)
Der kanonische Artikel über Mocks und Stubs, Interaktionsverifikation
und Zustandsverifikation und klassizistisches und mockistisches TDD,
ist der Artikel "Mocks aren't Stubs" von Martin Fowler:
<http://MartinFowler.Com/articles/mocksArentStubs>
Hinweis: dieser Artikel macht tatsächlich eine relativ strenge
Unterscheidung zwischen Mocks, Stubs, Fakes und Dummies (Spies sind
eine neuere Erfindung und werden im Artikel nicht erwähnt), aber ich
glaube dass diese Unterschiede tatsächlich wesentlich kleiner sind als
in dem Artikel dargestellt. Was auch daran liegen kann, dass es sich
hierbei um ein quasi-wissenschaftliches Essay handelt. Oder dass der
Autor, obwohl er ein alter Smalltalker und neuer Ruby-Fan ist,
beruflich hauptsächlich Java und C# verwendet. Oder, dass er nur
Frameworks benutzt, die eine strikte Trennung zwischen Mocks und Stubs
aufweisen.
(Ich glaube, wer einmal ein signifikantes testgetriebenes Projekt in
einer hoch-dynamischen, hoch-reflektiven, hoch-flexiblen Sprache wie
Ruby, ECMAScript, Io, Ioke, Smalltalk, Self, Newspeak, Perl, Python,
Scheme, Lisp, Clojure etc. entwickelt hat, wird erkennen, wie schnell
die klaren Grenzen, die von statischen Mock/Stub-Frameworks in
statischen Sprachen künstlich gezogen werden, verschwimmen. Aber das
ist selbstverständlich nur meine persönliche Meinung.)
jwm
Christian schrieb:
> > Worin sollen sich ein "Stub" von einem "Mock" unterscheiden?
Du antwortest zunächst darauf mit: "Gar nicht."
Später schreibst Du: "Ein zweiter Unterschied zwischen
Mocks und Stubs zeigt sich [...]".
Das ist IMHO widersprüchlich, zumal in der Literatur
klar von Unterschieden die Sprache ist.
> http://MartinFowler.Com/articles/mocksArentStubs
das hatten wir schon, aber doppelt hält
natürlich besser. Das ist aber auch nur ein Beispiel.
Es gibt genügend weitere professionelle und auch aktuelle
Artikel, die klare Unterschiede zwischen Mock und Stub
sehen.
Das "Gar nicht" beschreibt J�rg aber noch genauer:
| Genauer: das kannst nur du sagen, denn Mocks und Stubs unterscheiden
| sich ausschlie�lich in deiner Intention; es gibt keinerlei
| intrinsische Unterschiede.
--
M S Herfried K. Wagner
M V P <URL:http://dotnet.mvps.org/>
V B <URL:http://dotnet.mvps.org/dotnet/faqs/>
Du kannst also lesen.
Das "ausschliesslich" widerspricht auch wieder dem
"Ein zweiter Unterschied zwischen [...]".
AFAIK gibt es klare Unterschiede zwischen Mocks und Stubs.
Aber es scheint wohl immernoch so zu sein:
(aus dem von J�rg falsch verlinktem (in meinem Posting
noch richtigen) Artikel von Fowler:
"many people easily confused mock objects
with the common testing notion of using stubs".
an dessen Unterschieds-Beschreibung er "nicht glaubt".
Es ist aber nicht nur Fowler, der diese Unterschiede so sieht.
EOT.
vielen Dank für die umfangreichen Informtionen.
Viele Grüße
Christian
"Jörg W Mittag" wrote:
> .
>
vielen Dank für die Infos und die Links.
Viele Grüße
Christian
"FrankDzaebel" wrote:
> .
>
[Interessante Abhandlung gesnippt]
> (Ich glaube, wer einmal ein signifikantes testgetriebenes Projekt in
> einer hoch-dynamischen, hoch-reflektiven, hoch-flexiblen Sprache wie
> Ruby, ECMAScript, Io, Ioke, Smalltalk, Self, Newspeak, Perl, Python,
> Scheme, Lisp, Clojure etc. entwickelt hat, wird erkennen, wie schnell
> die klaren Grenzen, die von statischen Mock/Stub-Frameworks in
> statischen Sprachen künstlich gezogen werden, verschwimmen. Aber das
> ist selbstverständlich nur meine persönliche Meinung.)
Dein Post ist mal eine interessante und erfrischende Ansicht zu dem
Thema - gerade weil es Deine persönliche Meinung ist :-)
--
Immo Landwerth