it-swarm.com.de

Wie genau sollten Unit-Tests geschrieben werden, ohne sich ausgiebig zu verspotten?

Soweit ich weiß, besteht der Zweck von Komponententests darin, Codeeinheiten isoliert zu testen . Das bedeutet, dass:

  1. Sie sollten nicht durch nicht verwandten Code an anderer Stelle in der Codebasis geändert werden.
  2. Im Gegensatz zu Integrationstests (die in Haufen brechen können) sollte nur ein Komponententest durch einen Fehler in der getesteten Einheit unterbrochen werden.

All dies impliziert, dass jede externe Abhängigkeit einer getesteten Einheit verspottet werden sollte. Und ich meine alle äußeren Abhängigkeiten, nicht nur die "äußeren Schichten" wie Netzwerk, Dateisystem, Datenbank usw.

Dies führt zu einer logischen Schlussfolgerung, dass praktisch jeder Komponententest verspotten muss . Auf der anderen Seite enthüllt eine schnelle Google-Suche nach Spott Unmengen von Artikeln, die behaupten, dass "Spott ein Codegeruch ist" und größtenteils (wenn auch nicht vollständig) vermieden werden sollten.

Nun zu den Fragen.

  1. Wie sollen Unit-Tests richtig geschrieben werden?
  2. Wo genau liegt die Grenze zwischen ihnen und den Integrationstests?

pdate 1

Bitte beachten Sie den folgenden Pseudocode:

class Person {
    constructor(calculator) {}

    calculate(a, b) {
        const sum = this.calculator.add(a, b);

        // do some other stuff with the `sum`
    }
}

Kann ein Test, der die Person.calculate Methode ohne Verspottung der Calculator Abhängigkeit (vorausgesetzt, dass Calculator eine Lightweight-Klasse ist, die nicht auf "die Außenwelt" zugreift) als Unit-Test betrachtet werden?

82
Alexander Lomia

bei Unit-Tests geht es darum, Code-Einheiten isoliert zu testen.

Martin Fowler über nit Test

Unit-Tests werden in der Softwareentwicklung häufig erwähnt und sind ein Begriff, mit dem ich während meiner gesamten Zeit beim Schreiben von Programmen vertraut war. Wie die meisten Terminologien für die Softwareentwicklung ist sie jedoch sehr schlecht definiert, und ich sehe, dass es häufig zu Verwirrung kommen kann, wenn die Leute denken, dass sie enger definiert ist als sie tatsächlich ist.

Was Kent Beck in Test Driven Development, By Example geschrieben hat

Ich nenne sie "Unit-Tests", aber sie stimmen nicht sehr gut mit der akzeptierten Definition von Unit-Tests überein

Jede Behauptung, dass "der Punkt der Einheitentests ist", hängt stark davon ab, welche Definition von "Einheitentest" in Betracht gezogen wird.

Wenn Sie der Ansicht sind, dass Ihr Programm aus vielen kleinen Einheiten besteht, die voneinander abhängen, und wenn Sie sich auf einen Stil beschränken, der jede Einheit isoliert testet, ist eine Menge Testdoppel unvermeidlich Fazit.

Die widersprüchlichen Ratschläge, die Sie sehen, stammen von Personen, die unter anderen Annahmen arbeiten.

Wenn Sie beispielsweise Tests schreiben, um Entwickler während des Refactorings zu unterstützen, und Aufteilen einer Einheit in zwei ein Refactoring ist, das unterstützt werden sollte, muss etwas gegeben werden. Vielleicht braucht diese Art von Test einen anderen Namen? Oder vielleicht brauchen wir ein anderes Verständnis von "Einheit".

Vielleicht möchten Sie vergleichen:

Kann ein Test, der die Person.calculate-Methode testet, ohne die Calculator-Abhängigkeit zu verspotten (vorausgesetzt, der Calculator ist eine Lightweight-Klasse, die nicht auf "die Außenwelt" zugreift), als Komponententest betrachtet werden?

Ich denke, das ist die falsche Frage. Es ist wieder ein Argument über Labels, wenn ich glaube, dass uns Eigenschaften wichtig sind.

Wenn ich Änderungen am Code einführe, ist mir die Isolierung von Tests egal - ich weiß bereits, dass "der Fehler" irgendwo in meinem aktuellen Stapel nicht verifizierter Änderungen liegt. Wenn ich die Tests häufig ausführe, beschränke ich die Tiefe dieses Stapels, und es ist trivial, den Fehler zu finden (im Extremfall werden die Tests nach jeder Bearbeitung ausgeführt - die maximale Tiefe des Stapels beträgt eins). Das Ausführen der Tests ist jedoch nicht das Ziel - es handelt sich um eine Unterbrechung. Daher ist es sinnvoll, die Auswirkungen der Unterbrechung zu verringern. Eine Möglichkeit, die Unterbrechung zu verringern, besteht darin, sicherzustellen, dass die Tests schnell sind ( Gary Bernhardt schlägt 300 ms vor , aber ich habe unter meinen Umständen nicht herausgefunden, wie das geht).

Beim Aufrufen von Calculator::add erhöht die zum Ausführen des Tests erforderliche Zeit (oder eine der anderen wichtigen Eigenschaften für diesen Anwendungsfall) nicht wesentlich, dann würde ich kein Testdoppel verwenden - es bietet keine Vorteile, die die Kosten überwiegen .

Beachten Sie hier die beiden Annahmen: einen Menschen als Teil der Kostenbewertung und den kurzen Stapel nicht überprüfter Änderungen in der Nutzenbewertung. Unter Umständen, unter denen diese Bedingungen nicht zutreffen, ändert sich der Wert der "Isolation" erheblich.

Siehe auch Hot Lava von Harry Percival.

59
VoiceOfUnreason

Wie genau sollten Unit-Tests geschrieben werden, ohne sich ausgiebig zu verspotten?

Durch Minimierung von Nebenwirkungen in Ihrem Code.

Wenn calculator beispielsweise mit einer Web-API kommuniziert, erstellen Sie in Ihrem Beispielcode entweder fragile Tests, die auf der Interaktion mit dieser Web-API beruhen, oder Sie erstellen eine Verspottung davon. Wenn es sich jedoch um einen deterministischen, zustandsfreien Satz von Berechnungsfunktionen handelt, verspotten Sie ihn nicht (und sollten es auch nicht). Wenn Sie dies tun, riskieren Sie, dass sich Ihr Mock anders verhält als der echte Code, was zu Fehlern in Ihren Tests führt.

Mocks sollten nur für Code benötigt werden, der in das Dateisystem, Datenbanken, URL-Endpunkte usw. liest/schreibt. die von der Umgebung abhängen, unter der Sie ausgeführt werden; oder die sehr zustandsbehaftet und nicht deterministisch sind. Wenn Sie also diese Teile des Codes auf ein Minimum beschränken und sie hinter Abstraktionen verstecken, sind sie leicht zu verspotten und der Rest Ihres Codes vermeidet die Notwendigkeit von Verspottungen.

Für die Codepunkte, die Nebenwirkungen haben, lohnt es sich, Tests zu schreiben, die verspotten, und Tests, die dies nicht tun. Letztere benötigen jedoch Pflege, da sie von Natur aus zerbrechlich und möglicherweise langsam sind. Daher möchten Sie sie möglicherweise nur über Nacht auf einem CI-Server ausführen und nicht jedes Mal, wenn Sie Ihren Code speichern und erstellen. Die früheren Tests sollten jedoch so oft wie möglich durchgeführt werden. Ob jeder Test dann ein Einheits- oder Integrationstest ist, wird akademisch und vermeidet "Flammenkriege" darüber, was ein Einheitentest ist und was nicht.

40
David Arno

Diese Fragen sind in ihrer Schwierigkeit sehr unterschiedlich. Nehmen wir zuerst Frage 2.

Unit-Tests und Integrationstests sind klar voneinander getrennt. Ein Komponententest testet eine Einheit (Methode oder Klasse) und verwendet andere Einheiten nur so oft wie nötig, um dieses Ziel zu erreichen. Spott kann notwendig sein, aber es ist nicht der Punkt des Tests. Ein Integrationstest testet die Interaktion zwischen verschiedenen tatsächlichen Einheiten. Dieser Unterschied ist der ganze Grund, warum wir brauchen sowohl Unit- als auch Integrationstests - wenn einer die Arbeit des anderen gut genug erledigt hat, würden wir das nicht tun, aber es hat sich herausgestellt, dass es normalerweise effizienter ist, zwei zu verwenden spezialisierte Werkzeuge statt eines verallgemeinerten Werkzeugs.

Nun zur wichtigen Frage: Wie sollten Sie Unit-Tests durchführen? Wie oben erwähnt, sollten Unit-Tests Hilfsstrukturen konstruieren nur soweit erforderlich. Oft ist es einfacher, eine Scheindatenbank zu verwenden als Ihre reale Datenbank oder sogar jede reale Datenbank. Das Verspotten an sich hat jedoch keinen Wert. Wenn es häufig vorkommt, dass es tatsächlich einfacher ist, tatsächliche Komponenten einer anderen Ebene als Eingabe für einen Unit-Test auf mittlerer Ebene zu verwenden. Wenn ja, zögern Sie nicht, sie zu verwenden.

Viele Praktiker befürchten, dass ein Defekt in Einheit A an mehreren Stellen zu Testfehlern führt, wenn Unit Test B Klassen wiederverwendet, die bereits von Unit Test A getestet wurden. Ich halte dies für kein Problem: Eine Testsuite muss erfolgreich sein 100%, um Ihnen die Sicherheit zu geben, die Sie benötigen. Es ist also kein großes Problem, zu viele Fehler zu haben - schließlich Sie - do einen Defekt haben. Das einzige kritische Problem wäre, wenn auch ein Defekt ausgelöst würde wenige Fehler.

Machen Sie deshalb keine Religion des Spottes. Es ist ein Mittel, kein Zweck. Wenn Sie also die zusätzliche Anstrengung vermeiden können, sollten Sie dies tun.

30
Kilian Foth

OK, um Ihre Fragen direkt zu beantworten:

Wie sollen Unit-Tests richtig geschrieben werden?

Wie Sie sagen, sollten Sie sich über Abhängigkeiten lustig machen und nur die betreffende Einheit testen.

Wo genau liegt die Grenze zwischen ihnen und Integrationstests?

Ein Integrationstest ist ein Komponententest, bei dem Ihre Abhängigkeiten nicht verspottet werden.

Kann ein Test, der die Person.calculate-Methode testet, ohne den Rechner zu verspotten, als Komponententest betrachtet werden?

Nein. Sie müssen die Taschenrechnerabhängigkeit in diesen Code einfügen und haben die Wahl zwischen einer verspotteten oder einer echten Version. Wenn Sie einen verspotteten Test verwenden, handelt es sich um einen Komponententest. Wenn Sie einen echten Test verwenden, handelt es sich um einen Integrationstest.

Allerdings eine Einschränkung. Interessiert es Sie wirklich, wie die Leute denken, dass Ihre Tests heißen sollten?

Aber Ihre eigentliche Frage scheint folgende zu sein:

eine schnelle Google-Suche nach Spott enthüllt Tonnen von Artikeln, die behaupten, dass "Spott ein Code-Geruch ist" und größtenteils (wenn auch nicht vollständig) vermieden werden sollten.

Ich denke, das Problem hier ist, dass viele Leute Mocks verwenden, um die Abhängigkeiten vollständig neu zu erstellen. Zum Beispiel könnte ich den Rechner in Ihrem Beispiel als verspotten

public class MockCalc : ICalculator
{
     public Add(int a, int b) { return 4; }
}

Ich würde so etwas nicht machen:

myMock = Mock<ICalculator>().Add((a,b) => {return a + b;})
myPerson.Calculate()
Assert.WasCalled(myMock.Add());

Ich würde das argumentieren, das wäre "Testen meines Mocks" oder "Testen der Implementierung". Ich würde sagen "Schreibe keine Mocks! * so".

Andere Leute würden mir nicht zustimmen, wir würden in unseren Blogs massive Flammenkriege über den besten Weg zum Spott beginnen, was wirklich keinen Sinn ergeben würde, wenn Sie nicht den gesamten Hintergrund der verschiedenen Ansätze verstehen und wirklich nicht viel Wert bieten an jemanden, der nur gute Tests schreiben will.

7
Ewan
  1. Wie sollen Unit-Tests richtig durchgeführt werden?

Meine Faustregel lautet: Richtige Unit-Tests:

  • Sind gegen Schnittstellen codiert, nicht gegen Implementierungen . Dies hat viele Vorteile. Zum einen wird sichergestellt, dass Ihre Klassen dem Abhängigkeitsinversionsprinzip von SOLID folgen. Dies ist auch das, was Ihre anderen Klassen tun ( richtig ?), sodass Ihre Tests dasselbe tun sollten. Auf diese Weise können Sie auch mehrere Implementierungen derselben Schnittstelle testen, während Sie einen Großteil des Testcodes wiederverwenden (nur die Initialisierung und einige Zusicherungen würden sich ändern).
  • Sind in sich geschlossen . Wie Sie sagten, können Änderungen an externem Code das Testergebnis nicht beeinflussen. Daher können Komponententests zur Erstellungszeit ausgeführt werden. Dies bedeutet, dass Sie Mocks benötigen, um Nebenwirkungen zu entfernen. Wenn Sie jedoch dem Prinzip der Abhängigkeitsinversion folgen, sollte dies relativ einfach sein. Gute Test-Frameworks wie Spock können verwendet werden, um dynamisch Scheinimplementierungen jeder Schnittstelle bereitzustellen, die in Ihren Tests mit minimaler Codierung verwendet werden soll. Dies bedeutet, dass jede Testklasse nur Code aus genau einer Implementierungsklasse sowie dem Testframework (und möglicherweise Modellklassen ["Beans"]) ausführen muss.
  • Benötigen Sie keine separate laufende Anwendung . Wenn der Test "mit etwas sprechen" muss, sei es mit einer Datenbank oder einem Webdienst, handelt es sich um einen Integrationstest, nicht um einen Komponententest. Ich ziehe die Grenze bei Netzwerkverbindungen oder im Dateisystem. Eine rein speicherinterne SQLite-Datenbank zum Beispiel ist meiner Meinung nach ein faires Spiel für einen Unit-Test, wenn Sie ihn wirklich brauchen.

Wenn es Dienstprogrammklassen aus Frameworks gibt, die das Testen von Einheiten erschweren, kann es sogar nützlich sein, sehr einfache "Wrapper" -Schnittstellen und -Klassen zu erstellen, um das Verspotten dieser Abhängigkeiten zu erleichtern. Diese Wrapper würden dann nicht unbedingt Unit-Tests unterzogen.

  1. Wo genau liegt die Grenze zwischen ihnen [Unit-Tests] und Integrationstests?

Ich habe diese Unterscheidung als die nützlichste empfunden:

  • Unit-Tests simulieren "Benutzercode" und verifizieren das Verhalten von Implementierungsklassen anhand des gewünschten Verhaltens und der Semantik von Schnittstellen auf Codeebene =.
  • Integrationstests simulieren den Benutzer und überprüfen das Verhalten der laufenden Anwendung gegen bestimmte Anwendungsfälle und/oder formale APIs. Für einen Webdienst wäre der "Benutzer" eine Clientanwendung.

Hier gibt es eine Grauzone. Wenn Sie beispielsweise eine Anwendung in einem Docker-Container ausführen und die Integrationstests als letzte Phase eines Builds ausführen und den Container anschließend zerstören können, ist es in Ordnung, diese Tests als "Komponententests" einzuschließen? Wenn dies Ihre brennende Debatte ist, sind Sie an einem ziemlich guten Ort.

  1. Stimmt es, dass praktisch jeder Unit-Test verspotten muss?

Nein. Einige einzelne Testfälle betreffen Fehlerbedingungen, z. B. das Übergeben von null als Parameter und das Überprüfen, ob Sie eine Ausnahme erhalten. Viele solcher Tests erfordern keine Verspottungen. Implementierungen, die keine Nebenwirkungen haben, z. B. Zeichenfolgenverarbeitung oder mathematische Funktionen, erfordern möglicherweise keine Verspottungen, da Sie einfach die Ausgabe überprüfen. Aber die meisten Klassen, die es wert sind, gesehen zu werden, erfordern mindestens einen Mock irgendwo im Testcode. (Je weniger, desto besser.)

Das von Ihnen erwähnte Problem "Codegeruch" tritt auf, wenn Sie eine Klasse haben, die zu kompliziert ist und eine lange Liste von Scheinabhängigkeiten erfordert, um Ihre Tests zu schreiben. Dies ist ein Hinweis darauf, dass Sie die Implementierung umgestalten und aufteilen müssen, damit jede Klasse einen geringeren Platzbedarf und eine klarere Verantwortung hat und daher leichter getestet werden kann. Dies wird auf lange Sicht die Qualität verbessern.

Nur ein Komponententest sollte durch einen Fehler in der getesteten Einheit unterbrochen werden.

Ich halte dies nicht für eine vernünftige Erwartung, da dies gegen die Wiederverwendung wirkt. Möglicherweise haben Sie eine private -Methode, die beispielsweise von mehreren public -Methoden aufgerufen wird, die von Ihrer Schnittstelle veröffentlicht werden. Ein in diese eine Methode eingeführter Fehler kann dann zu mehreren Testfehlern führen. Dies bedeutet nicht, dass Sie denselben Code in jede public -Methode kopieren sollten.

4
wberry
  1. Sie sollten nicht durch nicht verwandten Code an anderer Stelle in der Codebasis geändert werden.

Ich bin mir nicht sicher, wie nützlich diese Regel ist. Wenn eine Änderung in einer Klasse/Methode/was auch immer das Verhalten einer anderen im Produktionscode stören kann, dann sind die Dinge in Wirklichkeit Kollaborateure und nicht unabhängig. Wenn Ihre Tests nicht funktionieren und Ihr Produktionscode dies nicht tut, sind Ihre Tests verdächtig.

  1. Im Gegensatz zu Integrationstests (die in Haufen brechen können) sollte nur ein Komponententest durch einen Fehler in der getesteten Einheit unterbrochen werden.

Ich würde diese Regel auch mit Argwohn betrachten. Wenn Sie wirklich gut genug sind, um Ihren Code zu strukturieren und Ihre Tests so zu schreiben, dass ein Fehler genau einen Unit-Test-Fehler verursacht, dann sagen Sie, dass Sie bereits alle potenziellen Fehler identifiziert haben, selbst wenn sich die Codebasis weiterentwickelt, um Fälle zu verwenden, die Sie verwenden habe nicht erwartet.

Wo genau liegt die Grenze zwischen ihnen und Integrationstests?

Ich denke nicht, dass das ein wichtiger Unterschied ist. Was ist überhaupt eine Codeeinheit?

Versuchen Sie, Einstiegspunkte zu finden, an denen Sie Tests schreiben können, die im Hinblick auf die Problemdomäne/Geschäftsregeln, die diese Ebene des Codes (== --- ==) betreffen, nur "sinnvoll" sind beschäftigt sich mit. Oft sind diese Tests etwas "funktional" - geben Sie eine Eingabe ein und testen Sie, ob die Ausgabe wie erwartet ist. Wenn die Tests ein gewünschtes Verhalten des Systems ausdrücken, bleiben sie oft recht stabil, selbst wenn sich der Produktionscode weiterentwickelt und überarbeitet wird.

Wie genau sollten Unit-Tests geschrieben werden, ohne sich ausgiebig zu verspotten?

Lesen Sie nicht zu viel in die Word-Einheit und tendieren Sie dazu, Ihre realen Produktionsklassen in Tests zu verwenden, ohne sich zu viele Sorgen zu machen, wenn Sie mehr als eine davon in einen Test einbeziehen. Wenn einer von ihnen schwer zu bedienen ist (weil er viel Initialisierung erfordert oder auf eine echte Datenbank/einen E-Mail-Server usw. zugreifen muss), sollten Sie sich Gedanken über Spott/Fälschung machen.

Zunächst einige Definitionen:

Ein Komponententest testet Einheiten isoliert von anderen Einheiten. Aber was dies bedeutet, wird von keiner maßgeblichen Quelle konkret definiert. Definieren wir es also etwas besser: Wenn E/A-Grenzen überschritten werden (ob das ich/O ist eine Netzwerk-, Festplatten-, Bildschirm- oder UI-Eingabe. Es gibt einen halbzielen Ort, an dem wir eine Linie ziehen können. Wenn der Code von E/A abhängt, überschreitet er eine Einheitengrenze und muss daher die für diese E/A verantwortliche Einheit verspotten.

Unter dieser Definition sehe ich keinen zwingenden Grund, Dinge wie reine Funktionen zu verspotten, was bedeutet, dass sich Unit-Tests für reine Funktionen oder Funktionen ohne Nebenwirkungen eignen.

Wenn Sie Einheiten mit Effekten testen möchten, sollten die für die Effekte verantwortlichen Einheiten verspottet werden. Vielleicht sollten Sie stattdessen einen Integrationstest in Betracht ziehen. Die kurze Antwort lautet also: "Wenn Sie sich lustig machen müssen, fragen Sie sich, ob Sie wirklich einen Integrationstest benötigen." Aber hier gibt es eine bessere, längere Antwort, und das Kaninchenloch geht viel tiefer. Mocks sind vielleicht mein Lieblingscodegeruch, weil es so viel zu lernen gibt.

Code riecht

Dazu wenden wir uns an Wikipedia:

Bei der Computerprogrammierung ist ein Codegeruch ein Merkmal im Quellcode eines Programms, das möglicherweise auf ein tieferes Problem hinweist.

Es geht später weiter ...

"Gerüche sind bestimmte Strukturen im Code, die auf Verstöße gegen grundlegende Designprinzipien hinweisen und sich negativ auf die Designqualität auswirken." Suryanarayana, Girish (November 2014). Refactoring für Software-Design-Gerüche. Morgan Kaufmann. p. 258.

Code-Gerüche sind normalerweise keine Fehler. Sie sind technisch nicht inkorrekt und beeinträchtigen die Funktionsfähigkeit des Programms nicht. Stattdessen weisen sie auf Designschwächen hin, die die Entwicklung verlangsamen oder das Risiko von Fehlern oder Ausfällen in der Zukunft erhöhen können.

Mit anderen Worten, nicht alle Codegerüche sind schlecht. Stattdessen sind sie häufige Anzeichen dafür, dass etwas möglicherweise nicht in seiner optimalen Form ausgedrückt wird, und der Geruch kann eine Gelegenheit zur Verbesserung des fraglichen Codes anzeigen.

Im Falle einer Verspottung zeigt der Geruch an, dass die Einheiten, die scheinbar Verspottungen fordern, von den zu verspottenden Einheiten abhängen. Dies kann ein Hinweis darauf sein, dass wir das Problem nicht in atomar lösbare Teile zerlegt haben und dass auf einen Konstruktionsfehler in der Software hinweisen könnte.

Die Essenz jeder Softwareentwicklung besteht darin, ein großes Problem in kleinere, unabhängige Teile zu zerlegen (Zerlegung) und die Lösungen zusammenzustellen, um eine Anwendung zu bilden, die das große Problem löst (Zusammensetzung).

Verspottung ist erforderlich, wenn die Einheiten, mit denen das große Problem in kleinere Teile zerlegt wird, voneinander abhängen. Anders ausgedrückt, Spott ist erforderlich, wenn unsere vermeintlichen atomaren Kompositionseinheiten nicht wirklich atomar sind und unsere Zerlegungsstrategie das größere Problem nicht in kleinere, unabhängige zu lösende Probleme.

Was das Verspotten eines Codes riecht, ist nicht, dass das Verspotten von Natur aus falsch ist - manchmal ist es sehr nützlich. Was es zu einem Codegeruch macht, ist, dass es auf eine problematische Kopplungsquelle in Ihrer Anwendung hinweisen kann. Manchmal ist das Entfernen dieser Kopplungsquelle viel produktiver als das Schreiben eines Modells.

Es gibt viele Arten der Kopplung, und einige sind besser als andere. Wenn Sie verstehen, dass Mocks ein Codegeruch sind, können Sie lernen, die schlimmsten Arten früh im Anwendungsdesign-Lebenszyklus zu identifizieren und zu vermeiden ) vor entwickelt sich der Geruch zu etwas Schlimmerem.

2
Eric Elliott

Spott sollte nur als letzter Ausweg verwendet werden, auch bei Unit-Tests.

Eine Methode ist keine Einheit, und selbst eine Klasse ist keine Einheit. Eine Einheit ist jede logische Trennung von Code, die sinnvoll ist, unabhängig davon, wie Sie sie nennen. Ein wichtiges Element für gut getesteten Code ist die freie Umgestaltung. Ein Teil der freien Umgestaltung bedeutet, dass Sie Ihre Tests nicht ändern müssen, um dies zu tun. Je mehr Sie sich lustig machen, desto mehr müssen Sie Ihre Tests ändern, wenn Sie umgestalten. Wenn Sie die Methode als Einheit betrachten, müssen Sie Ihre Tests jedes Mal ändern, wenn Sie den Refactor durchführen. Und wenn Sie die Klasse als Einheit betrachten, müssen Sie Ihre Tests jedes Mal ändern, wenn Sie eine Klasse in mehrere Klassen aufteilen möchten. Wenn Sie Ihre Tests umgestalten müssen, um Ihren Code umzugestalten, entscheiden sich die Benutzer dafür, ihren Code nicht umzugestalten. Dies ist fast das Schlimmste, was einem Projekt passieren kann. Es ist wichtig, dass Sie eine Klasse in mehrere Klassen aufteilen können, ohne Ihre Tests umgestalten zu müssen. Andernfalls erhalten Sie übergroße Spaghetti-Klassen mit 500 Zeilen. Wenn Sie Methoden oder Klassen mit Unit-Tests als Ihre Einheiten behandeln, führen Sie wahrscheinlich keine objektorientierte Programmierung durch, sondern eine Art mutierte funktionale Programmierung mit Objekten.

Das Isolieren Ihres Codes für einen Komponententest bedeutet nicht, dass Sie alles außerhalb verspotten. Wenn ja, müssten Sie sich über den Mathematikunterricht Ihrer Sprache lustig machen, und absolut niemand hält das für eine gute Idee. Interne Abhängigkeiten sollten nicht anders behandelt werden als externe Abhängigkeiten. Sie vertrauen darauf, dass sie gut getestet sind und so funktionieren, wie sie sollen. Der einzige wirkliche Unterschied besteht darin, dass Sie, wenn Ihre internen Abhängigkeiten Ihre Module beschädigen, aufhören können, was Sie tun, um das Problem zu beheben, anstatt ein Problem auf GitHub veröffentlichen zu müssen und entweder in eine Codebasis zu graben, die Sie nicht verstehen, um es zu beheben oder hoffe auf das Beste.

Das Isolieren Ihres Codes bedeutet nur, dass Sie Ihre internen Abhängigkeiten wie Black Boxes behandeln und keine Dinge testen, die in ihnen geschehen. Wenn Sie Modul B haben, das Eingaben von 1, 2 oder 3 akzeptiert, und Modul A haben, das es aufruft, lassen Sie Ihre Tests für Modul A nicht jede dieser Optionen ausführen. Wählen Sie einfach eine aus und verwenden Sie diese. Dies bedeutet, dass Ihre Tests für Modul A die verschiedenen Arten der Behandlung der Antworten von Modul B testen sollten, nicht die Dinge, die Sie an Modul B weitergeben.

Wenn Ihr Controller also ein komplexes Objekt an eine Abhängigkeit übergibt und diese Abhängigkeit mehrere mögliche Dinge bewirkt, speichert sie möglicherweise in der Datenbank und gibt möglicherweise eine Vielzahl von Fehlern zurück. Ihr Controller überprüft jedoch lediglich, ob sie zurückgegeben wird Wenn Sie einen Fehler haben oder nicht und diese Informationen weitergeben, ist alles, was Sie in Ihrem Controller testen, ein Test, ob er einen Fehler zurückgibt und weitergibt, und ein Test, ob er keinen Fehler zurückgibt. Sie testen nicht, ob etwas in der Datenbank gespeichert wurde oder um welche Art von Fehler es sich handelt, da dies ein Integrationstest wäre. Sie müssen sich nicht über die Abhängigkeit lustig machen, um dies zu tun. Sie haben den Code isoliert.

1
TiggerToo