Wie viel Spott ist "genau richtig"?

10

Ich habe die Frage scherzhaft betitelt, weil ich sicher bin, dass "es darauf ankommt", aber ich habe einige spezifische Fragen.

Mein Team arbeitet mit Software, die viele tiefe Abhängigkeitsebenen aufweist, und hat sich daran gewöhnt, das Verspotten ziemlich ausführlich zu verwenden, um jedes Codemodul von den darunter liegenden Abhängigkeiten zu trennen.

Daher war ich überrascht, dass Roy Osherove in diesem Video vorgeschlagen hat, dass Sie nur etwa 5% der Zeit verspotten sollten. Ich würde vermuten, dass wir irgendwo zwischen 70-90% sitzen. Ich habe von Zeit zu Zeit auch andere ähnliche Anleitungen gesehen .

Ich sollte definieren, was ich als zwei Kategorien von "Integrationstests" betrachte, die so unterschiedlich sind, dass sie wirklich unterschiedliche Namen erhalten sollten: 1) In-Process-Tests, die mehrere Codemodule integrieren, und 2) Out-of-Process-Tests, die sprechen zu Datenbanken, Dateisystemen, Webdiensten usw. Es ist Typ 1, mit dem ich mich befasse, Tests, die mehrere Codemodule integrieren, die alle in Bearbeitung sind.

Ein Großteil der Community-Anleitungen, die ich gelesen habe, schlägt vor, dass Sie eine große Anzahl isolierter, feinkörniger Unit-Tests und eine kleine Anzahl grobkörniger End-to-End-Integrationstests bevorzugen sollten, da Unit-Tests Ihnen genaues Feedback darüber geben, wo genau Möglicherweise wurden Regressionen erstellt, aber die groben Tests, deren Einrichtung umständlich ist, überprüfen tatsächlich die End-to-End-Funktionalität des Systems.

Angesichts dessen scheint es notwendig zu sein, Spott ziemlich häufig zu verwenden, um diese separaten Codeeinheiten zu isolieren.

Gegeben ein Objektmodell wie folgt:

Geben Sie hier die Bildbeschreibung ein

... Bedenken Sie auch, dass die Abhängigkeitstiefe unserer Anwendung viel tiefer geht, als ich in dieses Bild passen könnte, sodass zwischen der 2-4-Ebene und der 5-13-Ebene mehrere Ebenen N liegen.

Wenn ich eine einfache logische Entscheidung testen möchte, die in Einheit 1 getroffen wird, und wenn jede Abhängigkeit vom Konstruktor in das Codemodul injiziert wird, hängt dies davon ab, dass beispielsweise 2, 3 und 4 Konstruktor in das Modul 1 in injiziert werden Im Bild würde ich viel lieber Mocks von 2, 3 und 4 in 1 injizieren.

Andernfalls müsste ich konkrete Instanzen von 2, 3 und 4 erstellen. Dies kann schwieriger sein als nur eine zusätzliche Eingabe. Oft haben 2, 3 und 4 Konstruktoranforderungen, deren Erfüllung schwierig sein kann, und gemäß dem Diagramm (und gemäß der Realität unseres Projekts) muss ich konkrete Instanzen von N bis 13 konstruieren, um die Konstruktoren von zu erfüllen 2, 3 und 4.

Diese Situation wird schwieriger, wenn ich 2, 3 oder 4 brauche, um mich auf eine bestimmte Weise zu verhalten, damit ich die einfache logische Entscheidung in # 1 testen kann. Möglicherweise muss ich den gesamten Objektgraphen / -baum auf einmal verstehen und "mental überlegen", damit sich 2, 3 oder 4 auf die erforderliche Weise verhalten. Es scheint oft viel einfacher zu sein, myMockOfModule2.Setup (x => x.GoLeftOrRight ()) auszuführen. Returns (new Right ()); Um zu testen, dass Modul 1 wie erwartet reagiert, wenn Modul 2 es auffordert, nach rechts zu gehen.

Wenn ich konkrete Instanzen von 2 ... N ... 13 zusammen testen würde, wären die Testaufbauten sehr groß und größtenteils dupliziert. Testfehler können die Orte von Regressionsfehlern möglicherweise nicht sehr gut lokalisieren. Tests wären nicht unabhängig (ein weiterer unterstützender Link ).

Zugegeben, es ist oft sinnvoll, die unterste Schicht eher zustandsbasiert als interaktionsbasiert zu testen, da diese Module selten weitere Abhängigkeiten aufweisen. Es scheint jedoch, dass Spott per Definition fast notwendig ist, um alle Module über dem untersten zu isolieren.

Kann mir angesichts all dessen jemand sagen, was mir fehlen könnte? Überbeansprucht unser Team Spott? Oder gibt es in typischen Leitlinien für Komponententests möglicherweise die Annahme, dass die Abhängigkeitsebenen in den meisten Anwendungen so flach sind, dass es tatsächlich sinnvoll ist, alle zusammen integrierten Codemodule zu testen (was unseren Fall "besonders" macht)? Oder vielleicht anders, begrenzt unser Team unsere begrenzten Kontexte nicht angemessen?

Ardave
quelle
Es klingt für mich so, als ob Ihre Anwendung von einer lockeren Kopplung profitieren könnte. en.wikipedia.org/wiki/Loose_coupling
Robert Harvey
1
Or is there perhaps some assumption in typical unit testing guidance that the layers of dependency in most applications will be shallow enough that it is indeed reasonable to test all of the code modules integrated together (making our case "special")? <- Dies.
Robert Harvey
Ebenfalls erwähnenswert: Der Zweck von Regressionstests (insbesondere Integrationstests) besteht darin, zu beweisen, dass Ihre Software immer noch funktioniert, und nicht unbedingt zu identifizieren, wo sie kaputt geht. Sie können dies mit der Fehlerbehebung tun, das Problem beheben und dann den spezifischen Bruch mit zusätzlichen Komponententests abdecken.
Robert Harvey
Ich hätte im ursprünglichen Beitrag klarer sagen sollen, dass Modul 1 nur I2, I3 und I4 kennt. Modul 2 kennt nur I5, I6 und I7. Es ist nur das fragwürdige Ziel des Testens ohne Verwendung von Mocks, dass ich konkrete 2, 3 und 4 zu 1 liefern würde, was zu den von mir beschriebenen Herausforderungen führt. Andernfalls verwenden wir in weit mehr als 5% der Fälle Mocks.
Ardave
Ich scherzte darüber, dass unser Fall "besonders" sei, nachdem ich einen Blog-Beitrag über viele Teams gelesen hatte, die sich wertvollen Konventionen widersetzten, weil sie fälschlicherweise der Meinung waren, ihre Situation sei "besonders". Wenn dies jedoch tatsächlich unser Fall ist, würde dies die Ungleichheit zwischen einigen der von mir gelesenen Community-Anleitungen und einigen tatsächlichen Erfahrungen meines Teams erklären. (die 5% vs 70-90%)
Ardave

Antworten:

4

Überbeansprucht unser Team Spott?

Nicht auf den ersten Blick.

Wenn Sie 1..13 Module haben, sollte jedes seine eigenen Komponententests haben und alle (nicht trivialen, nicht vertrauenswürdigen) Abhängigkeiten sollten durch Testversionen ersetzt werden. Das kann Mocks bedeuten, aber einige Leute sind pedantisch mit Namen, also Fälschungen, Shims, Null-Objekte ... einige Leute bezeichnen alle Testimplementierungen als "Mocks". Dies könnte die Quelle der Verwirrung darüber sein, wie viel "richtig" ist.

Persönlich nenne ich einfach alle Testobjekte "Mocks", weil es nicht oft nützlich ist, zwischen verschiedenen zu unterscheiden. Solange sie meine Unit-Tests schnell, isoliert und belastbar halten ... ist es mir egal, wie sie heißen.

Telastyn
quelle
Ich würde dann fragen , ob es irgendeine allgemeine Leitlinien für die da draußen , wenn es am besten ist, um Testcodemodule in Isolation vs. Prüfung mehr als ein Code - Modul, integriert zusammen. Es scheint, als würde ich mich, sobald ich zwei Module integriere, die ich sonst hätte isolieren können, einer Reihe unerwünschter Probleme aussetzen: Fehlende Ermittlung von Regressionsursachen / Fehlschlagen mehrerer Tests für eine einzelne Regression, übermäßige Testaufbauten usw. Ich habe meinen eigenen intuitiven Sinn ("Hören Sie sich die Tests an"), aber dies hat mich auf dem 70-90% Mock-Level belassen.
Ardave
1
@nono - Nach meiner Erfahrung sollten Sie aus den von Ihnen genannten Gründen alles isoliert testen . Die einzigen Dinge, die Sie nicht isoliert testen, sind Dinge, die Sie nicht können, weil sie direkt gegen ein Dateisystem oder eine andere externe Ressource gerichtet sind ( etwas muss das schließlich tun).
Telastyn
Nachdem Sie ein paar Tage darauf gekaut haben, scheint Ihre Erklärung die bestmögliche zu sein: Wenn man die strikte Definition von "Mock" als eine Art Testdoppel verwendet, das für die retrospektive Interaktion / Verhaltensüberprüfung verwendet wird, im Gegensatz zu einem Dummy-Testdoppel oder Ein Test-Double, das im Voraus konfiguriert wurde, um ein bestimmtes Verhalten zu simulieren. Dann konnte ich sehen, dass es bei 5% endet.
Ardave