Ich habe ein grundlegendes Verständnis der Mock und gefälschte Objekte, aber ich bin nicht sicher , habe ich das Gefühl , wann / wo spöttisch verwenden - vor allem , da es für dieses Szenario gelten würde hier .
unit-testing
language-agnostic
mocking
Esteban Araya
quelle
quelle
Antworten:
Ein Komponententest sollte einen einzelnen Codepfad mit einer einzelnen Methode testen. Wenn die Ausführung einer Methode außerhalb dieser Methode in ein anderes Objekt und wieder zurück übergeht, besteht eine Abhängigkeit.
Wenn Sie diesen Codepfad mit der tatsächlichen Abhängigkeit testen, sind Sie kein Komponententest. Sie testen die Integration. Das ist zwar gut und notwendig, aber kein Unit-Test.
Wenn Ihre Abhängigkeit fehlerhaft ist, kann Ihr Test so beeinflusst werden, dass ein falsches Positiv zurückgegeben wird. Beispielsweise können Sie der Abhängigkeit eine unerwartete Null übergeben, und die Abhängigkeit wird möglicherweise nicht auf Null gesetzt, wie dies dokumentiert ist. Ihr Test stößt nicht wie vorgesehen auf eine Nullargumentausnahme, und der Test besteht.
Möglicherweise fällt es Ihnen auch schwer, wenn nicht unmöglich, das abhängige Objekt zuverlässig dazu zu bringen, während eines Tests genau das zurückzugeben, was Sie möchten. Dazu gehört auch das Auslösen erwarteter Ausnahmen innerhalb von Tests.
Ein Mock ersetzt diese Abhängigkeit. Sie legen die Erwartungen für Aufrufe des abhängigen Objekts fest, legen die genauen Rückgabewerte fest, die es Ihnen geben soll, um den gewünschten Test durchzuführen, und / oder welche Ausnahmen Sie auslösen sollen, damit Sie Ihren Ausnahmebehandlungscode testen können. Auf diese Weise können Sie das betreffende Gerät einfach testen.
TL; DR: Verspotten Sie jede Abhängigkeit, die Ihr Komponententest berührt.
quelle
Scheinobjekte sind nützlich, wenn Sie Interaktionen zwischen einer zu testenden Klasse und einer bestimmten Schnittstelle testen möchten .
Zum Beispiel wollen wir testen , die Methode
sendInvitations(MailServer mailServer)
ruftMailServer.createMessage()
genau einmal, und fordert auchMailServer.sendMessage(m)
genau einmal, und keine andere Methoden werden auf der genannteMailServer
Schnittstelle. In diesem Fall können wir Scheinobjekte verwenden.Mit Scheinobjekten können wir anstelle eines Real-
MailServerImpl
oder TestversuchsTestMailServer
eine Scheinimplementierung derMailServer
Schnittstelle bestehen. Bevor wir einen Mock übergebenMailServer
, "trainieren" wir ihn, damit er weiß, welche Methodenaufrufe zu erwarten sind und welche Rückgabewerte zurückzugeben sind. Am Ende behauptet das Scheinobjekt, dass alle erwarteten Methoden wie erwartet aufgerufen wurden.Das hört sich theoretisch gut an, hat aber auch einige Nachteile.
Scheinmängel
Wenn Sie über ein Mock-Framework verfügen, sind Sie versucht, jedes Mal ein Mock-Objekt zu verwenden, wenn Sie eine Schnittstelle an die zu testende Klasse übergeben müssen. Auf diese Weise testen Sie Interaktionen, auch wenn dies nicht erforderlich ist . Leider ist ein unerwünschtes (versehentliches) Testen von Interaktionen schlecht, da Sie dann testen, ob eine bestimmte Anforderung auf eine bestimmte Weise implementiert ist, anstatt dass die Implementierung das erforderliche Ergebnis erbracht hat.
Hier ist ein Beispiel im Pseudocode. Nehmen wir an, wir haben eine
MySorter
Klasse erstellt und möchten sie testen:(In diesem Beispiel nehmen wir an, dass es sich nicht um einen bestimmten Sortieralgorithmus handelt, wie z. B. eine schnelle Sortierung, die wir testen möchten. In diesem Fall wäre der letztere Test tatsächlich gültig.)
In solch einem extremen Beispiel ist es offensichtlich, warum das letztere Beispiel falsch ist. Wenn wir die Implementierung von ändern, sorgt
MySorter
der erste Test hervorragend dafür, dass wir immer noch richtig sortieren. Das ist der springende Punkt bei den Tests - sie ermöglichen es uns, den Code sicher zu ändern. Andererseits bricht der letztere Test immer ab und ist aktiv schädlich; es behindert das Refactoring.Verspottet als Stummel
Mock-Frameworks ermöglichen häufig auch eine weniger strenge Verwendung, bei der nicht genau angegeben werden muss, wie oft Methoden aufgerufen werden sollen und welche Parameter erwartet werden. Sie ermöglichen das Erstellen von Scheinobjekten, die als Stubs verwendet werden .
Nehmen wir an, wir haben eine Methode
sendInvitations(PdfFormatter pdfFormatter, MailServer mailServer)
, die wir testen möchten. DasPdfFormatter
Objekt kann zum Erstellen der Einladung verwendet werden. Hier ist der Test:In diesem Beispiel kümmern wir uns nicht wirklich um das
PdfFormatter
Objekt, also trainieren wir es einfach, um jeden Aufruf leise anzunehmen und einige sinnvolle vordefinierte Rückgabewerte für alle Methoden zurückzugeben,sendInvitation()
die zu diesem Zeitpunkt aufgerufen werden. Wie sind wir auf genau diese Liste von Trainingsmethoden gekommen? Wir haben den Test einfach ausgeführt und die Methoden hinzugefügt, bis der Test bestanden wurde. Beachten Sie, dass wir den Stub so trainiert haben, dass er auf eine Methode reagiert, ohne eine Ahnung zu haben, warum sie aufgerufen werden muss. Wir haben einfach alles hinzugefügt, worüber sich der Test beschwert hat. Wir freuen uns, der Test besteht.Aber was passiert später, wenn wir uns ändern
sendInvitations()
oder eine andere Klasse, diesendInvitations()
verwendet, um ausgefallenere PDFs zu erstellen? Unser Test schlägt plötzlich fehl, weil jetzt mehr MethodenPdfFormatter
aufgerufen werden und wir unseren Stub nicht darauf trainiert haben, sie zu erwarten. Und normalerweise ist es nicht nur ein Test, der in solchen Situationen fehlschlägt, sondern jeder Test, der diesendInvitations()
Methode direkt oder indirekt verwendet. Wir müssen all diese Tests korrigieren, indem wir weitere Schulungen hinzufügen. Beachten Sie auch, dass wir nicht mehr benötigte Methoden nicht entfernen können, da wir nicht wissen, welche nicht benötigt werden. Auch hier behindert es das Refactoring.Auch die Lesbarkeit des Tests hat furchtbar gelitten. Es gibt dort viel Code, den wir nicht geschrieben haben, weil wir wollten, sondern weil wir mussten. Wir wollen diesen Code nicht dort haben. Tests, die Scheinobjekte verwenden, sehen sehr komplex aus und sind oft schwer zu lesen. Die Tests sollen dem Leser helfen, zu verstehen, wie die Klasse unter dem Test verwendet werden sollte, daher sollten sie einfach und unkompliziert sein. Wenn sie nicht lesbar sind, wird sie niemand pflegen. Tatsächlich ist es einfacher, sie zu löschen, als sie zu pflegen.
Wie kann man das beheben? Leicht:
PdfFormatterImpl
. Wenn dies nicht möglich ist, ändern Sie die realen Klassen, um dies zu ermöglichen. Die Nichtverwendung einer Klasse in Tests weist normalerweise auf einige Probleme mit der Klasse hin. Das Beheben der Probleme ist eine Win-Win-Situation - Sie haben die Klasse behoben und haben einen einfacheren Test. Auf der anderen Seite ist es kein Gewinn, es nicht zu reparieren und Mocks zu verwenden - Sie haben die reale Klasse nicht repariert und Sie haben komplexere, weniger lesbare Tests, die weitere Refactorings behindern.TestPdfFormatter
, das nichts tut. Auf diese Weise können Sie es für alle Tests einmal ändern, und Ihre Tests sind nicht mit langwierigen Setups überfüllt, in denen Sie Ihre Stubs trainieren.Alles in allem haben Scheinobjekte ihre Verwendung, aber wenn sie nicht sorgfältig verwendet werden, fördern sie häufig schlechte Praktiken, testen Implementierungsdetails, behindern das Refactoring und führen zu schwer lesbaren und schwer zu wartenden Tests .
Weitere Informationen zu Mock- Mängeln finden Sie auch unter Mock-Objekte: Mängel und Anwendungsfälle .
quelle
Faustregel:
Wenn die zu testende Funktion ein kompliziertes Objekt als Parameter benötigt und es schwierig wäre, dieses Objekt einfach zu instanziieren (wenn beispielsweise versucht wird, eine TCP-Verbindung herzustellen), verwenden Sie ein Modell.
quelle
Sie sollten ein Objekt verspotten, wenn Sie eine Abhängigkeit in einer Codeeinheit haben, die Sie testen möchten und die "nur so" sein muss.
Wenn Sie beispielsweise versuchen, eine Logik in Ihrer Codeeinheit zu testen, aber etwas von einem anderen Objekt abrufen müssen und was von dieser Abhängigkeit zurückgegeben wird, kann sich dies auf das auswirken, was Sie testen möchten - verspotten Sie dieses Objekt.
Einen großartigen Podcast zum Thema finden Sie hier
quelle