2010-11-05 4 views
10

Ich habe ein Projekt, ich versuche Unit-Tests und TDD-Praktiken mit zu lernen. Ich stelle fest, dass ich zu ziemlich verwirrenden Fällen komme, in denen ich lange Zeit Mocks für eine Utility-Klasse aufstelle, die praktisch überall verwendet wird.Ist es akzeptabel, eine "echte" Dienstprogrammklasse zu verwenden, anstatt in TDD zu spotten?

Von dem, was ich über Komponententests gelesen habe, wenn ich MyClass teste, sollte ich mich über andere Funktionen (wie von UtilityClass zur Verfügung gestellt) lustig machen. Ist es akzeptabel (unter der Annahme, dass UtilityClass selbst über umfangreiche Tests verfügt), nur die UtilityClass zu verwenden und keine Mocks für die verschiedenen Testfälle einzurichten?

Edit: Eines der Dinge, die ich mache viel Setup für. Ich modelliere eine Karte mit verschiedenen Objekten an verschiedenen Orten. Eine der gebräuchlichen Methoden in meiner Dienstprogrammklasse ist GetDistanceBetween. Ich teste Methoden, die Auswirkungen auf Dinge haben, abhängig von ihren individuellen Eigenschaften, also zum Beispiel einen Test, der alle Objekte innerhalb von 5 Einheiten eines Punktes auswählt und ein Alter über 3 mehrere Tests benötigt (alte Objekte in Reichweite, alte Objekte ignoriert) der Bereich, ignoriert junge Objekte in Reichweite, arbeitet korrekt mit Vielfachen von jedem Fall) und alle diese Tests müssen Setup der 'GetDistanceBetween' Methode. Multiplizieren Sie das mit jeder Methode, die GetDistanceBetween verwendet (fast jede) und die verschiedenen Ergebnisse, die die Methode unter verschiedenen Umständen zurückgeben sollte, und es wird viel Setup.

Ich kann sehen, wie ich dies weiter entwickeln, kann es mehr Dienstprogramm Klassenaufrufe, große Anzahl von Objekten und eine Menge von Setup auf diesen Schein-Dienstprogramm Klassen.

Antwort

20

Die Regel ist nicht "Spott alles", sondern "machen Tests einfach". Mocking sollte verwendet werden, wenn

  1. Sie können eine Instanz mit vertretbarem Aufwand nicht schaffen (sprich: Sie einen einzigen Methodenaufruf müssen aber die Instanz zu erstellen, benötigen Sie eine funktionierende Datenbank, eine DB-Verbindung und fünf andere Klassen).
  2. Die Erstellung der zusätzlichen Klassen ist teuer.
  3. Die zusätzlichen Klassen zurückkehren instabile Werte (wie die aktuelle Uhrzeit oder Primärschlüssel aus einer Datenbank)
+1

+1 für die Hervorhebung von "make tests simple" –

1

Nein, es ist nicht akzeptabel, weil Sie die Klasse nicht mehr isoliert testen, was einer der wichtigsten Aspekte eines Komponententests ist. Sie testen es mit seiner Abhängigkeit von diesem Dienstprogramm, selbst wenn das Dienstprogramm über eigene Tests verfügt. Um die Erstellung von Mock-Objekten zu vereinfachen, könnten Sie ein Mock-Framework verwenden. Hier sind einige beliebte Wahl:

Natürlich, wenn diese Utility-Klasse ist privat und kann nur im Rahmen der Klasse im Test verwendet werden Sie dann Ich muss es nicht verspotten.

+1

Testen einer Klasse isoliert ist unrealistisch. Wenn Sie das wirklich pushen wollten, müssten Sie auch java.lang.String nachmachen. –

+1

@Aaron, einverstanden, wenn ich in Isolation meinte, ich meinte isoliert von Code, den der Entwickler geschrieben hat. –

+0

Ich benutze bereits Moq, aber immer noch - wenn ich spezifische Antworten auf Methodenaufrufe brauche, muss ich diese einrichten. Die Setup-Fälle werden immer länger, wenn die Dinge komplizierter werden. –

4

In der Theorie sollten Sie alle Abhängigkeiten zu verspotten versuchen, aber es ist nie möglich, in der Realität. Z.B. Sie werden die Basisklassen aus der Standardbibliothek nicht verspotten. In Ihrem Fall, wenn die Utility-Klasse nur einige grundlegende Hilfsmethoden enthält, denke ich, dass ich mich nicht darum kümmern würde, sie zu verspotten.

Wenn es komplizierter ist als das oder verbindet sich mit einigen externen Ressourcen, müssen Sie es verspotten.Sie könnten in Erwägung ziehen, eine dedizierte Mock-Builder-Klasse zu erstellen, die Ihnen einen Standard-Mock (mit einigen definierten Standard-Stubs usw.) erstellt, sodass Sie die Code-Verdoppelung in allen Testklassen vermeiden können.

+0

Ja. Wenn das Dienstprogramm eine Verbindung mit externen Ressourcen wie URL herstellt, sollten Sie sich darüber lustig machen. – freeman

9

TDD ist nicht wirklich zu testen. Sein Hauptvorteil besteht darin, Ihnen dabei zu helfen, sauberen, benutzerfreundlichen Code zu entwickeln, den andere verstehen und ändern können. Wenn es der Hauptvorteil wäre, einen Test durchzuführen, wäre es möglich, Tests nach dem Code zu schreiben, anstatt vorher mit dem gleichen Effekt.

Wenn Sie können, empfehle ich Sie aufhören, sie als "Unit Tests" zu denken. Denken Sie stattdessen an Ihre Tests als Beispiele dafür, wie Sie Ihren Code verwenden können, sowie Beschreibungen seines Verhaltens, die zeigen, warum Ihr Code wertvoll ist.

Als Teil dieses Verhaltens möchte Ihre Klasse möglicherweise einige kollaborierende Klassen verwenden. Sie können diese ausspotten.

Wenn Ihre Dienstprogrammklassen ein zentraler Teil des Verhaltens Ihrer Klasse sind und Ihre Klasse keinen Wert hat oder ihr Verhalten ohne sie keinen Sinn ergibt, dann sollten Sie sie nicht ausspotten.

Aaron Digullas Antwort ist ziemlich gut; Ich würde jede seiner Antworten nach diesen Grundsätzen als umformulieren.

  1. Das Verhalten der mitwirkenden Klasse ist komplex und unabhängig vom Verhalten der Klasse der Sie interessiert

  2. Schaffung Die kollaborierende Klasse ist kein wertvoller Aspekt Ihrer Klasse und muss nicht zur Verantwortung Ihrer Klasse gehören.

  3. Die kollaborierende Klasse stellt einen Kontext zur Verfügung, der das Verhalten Ihrer Klasse ändert und daher Beispiele dafür zeigt, wie Sie sie verwenden können und welche Art von Verhalten Sie erwarten.

Hoffe das macht Sinn! Wenn Sie es mögen, werfen Sie einen Blick auf BDD, die diese Art von Wortschatz weit mehr als "Test" verwendet.

+0

"und Ihre Klasse hat keinen Wert oder ihr Verhalten macht keinen Sinn ohne sie, dann verspotten Sie sie nicht" - So in meinem Beispiel der Abstand zwischen Punkten zu bekommen, wo die Entfernung ein Schlüssel ist, der einen Teil der Funktion der Methode, die ich teste, würden Sie sagen: "Spott es nicht"? –

+0

Nun, Abstand liefert Kontext, also vielleicht. Eine gute Zeit, sich darüber lustig zu machen, wäre, wenn Sie unterschiedliche Strategien hätten - zum Beispiel, wenn Sie nach Entfernung oder nach Kosten berechnen könnten -, aber dann würde ich die Strategie und nicht nur die Entfernung verspotten. Im Moment konzentriere ich mich darauf, die Tests einfach zu lesen und zu verstehen. – Lunivore

1

Ja, es ist akzeptabel. Wichtig ist, dass die UtilityClass gründlich getestet wird und in der Lage ist, zu unterscheiden, ob ein Test aufgrund der getesteten Klasse oder aufgrund der UtilityClass fehlschlägt.

Das Testen einer Klasse isoliert bedeutet, dass sie in einer kontrollierten Umgebung in einer Umgebung getestet wird, in der man steuert, wie sich die Objekte verhalten.
Erstellen zu viele Objekte in einem Test-Setup ist ein Zeichen, dass die Umgebung zu groß wird und daher nicht genug kontrolliert wird. Die Zeit ist gekommen, um zu Scheinobjekten zurückzukehren.

Verwandte Themen