it-swarm.com.de

Ist testbarer Code besserer Code?

Ich versuche mich daran zu gewöhnen, regelmäßig Unit-Tests mit meinem Code zu schreiben, aber ich habe gelesen, dass zuerst es wichtig ist, testbaren Code zu schreiben . Diese Frage berührt SOLID Prinzipien des Schreibens von testbarem Code, aber ich möchte wissen, ob diese Designprinzipien nützlich (oder zumindest nicht schädlich) sind, ohne zu planen, Tests zu schreiben Zur Verdeutlichung: Ich verstehe, wie wichtig es ist, Tests zu schreiben. Dies ist keine Frage ihrer Nützlichkeit.

Um meine Verwirrung zu veranschaulichen, gibt der Autor in dem Stück , das diese Frage inspiriert hat, ein Beispiel für eine Funktion, die die aktuelle Zeit überprüft und je nach Zeit einen Wert zurückgibt. Der Autor weist darauf als fehlerhaften Code hin, da er die Daten (die Zeit) erzeugt, die er intern verwendet, was das Testen erschwert. Für mich scheint es jedoch übertrieben, die Zeit als Argument zu verwenden. Irgendwann muss der Wert initialisiert werden, und warum nicht dem Verbrauch am nächsten? Außerdem besteht der Zweck der Methode in meinem Kopf darin, einen Wert basierend auf aktuelle Zeit zurückzugeben, indem Sie ihn zu einem Parameter machen, den Sie implizieren, dass dieser Zweck geändert werden kann/sollte. Diese und andere Fragen lassen mich fragen, ob testbarer Code gleichbedeutend mit "besserem" Code ist.

Ist das Schreiben von testbarem Code auch ohne Tests eine gute Praxis ?


Ist testbarer Code tatsächlich stabiler? wurde als Duplikat vorgeschlagen. Bei dieser Frage geht es jedoch um die "Stabilität" des Codes, aber ich frage allgemeiner, ob der Code auch aus anderen Gründen wie Lesbarkeit, Leistung, Kopplung usw. überlegen ist.

103
WannabeCoder

In Bezug auf die gemeinsame Definition von Unit-Tests würde ich nein sagen. Ich habe einfachen Code gesehen, der verworren ist, weil er an das Test-Framework angepasst werden muss (z. B. Schnittstellen und IoC überall, was es schwierig macht, durch Schichten von Schnittstellenaufrufen und Daten zu folgen, die offensichtlich sein sollten durch Magie übergeben). Angesichts der Wahl zwischen leicht verständlichem Code oder einfach zu testendem Code entscheide ich mich jedes Mal für den wartbaren Code.

Dies bedeutet nicht, nicht zu testen, sondern die Werkzeuge an Ihre Bedürfnisse anzupassen, nicht umgekehrt. Es gibt andere Möglichkeiten zum Testen (aber schwer verständlicher Code ist immer schlechter Code). Sie können beispielsweise Komponententests erstellen, die weniger detailliert sind (z. B. Martin Fowler 's Einstellung, dass eine Einheit im Allgemeinen eine Klasse und keine Methode ist), oder Sie können Ihr Programm mit automatisierten Integrationstests starten stattdessen. Dies mag nicht so hübsch sein, wie Ihr Test-Framework mit grünen Häkchen aufleuchtet, aber wir sind nach dem getesteten Code, nicht nach der Gamifizierung des Prozesses, oder?

Sie können die Verwaltung Ihres Codes vereinfachen und dennoch für Komponententests geeignet sein, indem Sie gute Schnittstellen zwischen ihnen definieren und anschließend Tests schreiben, die die öffentliche Schnittstelle der Komponente ausüben. oder Sie könnten ein besseres Testframework erhalten (eines, das Funktionen zur Laufzeit ersetzt, um sie zu verspotten, anstatt zu verlangen, dass der Code mit vorhandenen Mocks kompiliert wird). Mit einem besseren Unit-Test-Framework können Sie die System-GetCurrentTime () -Funktionalität zur Laufzeit durch Ihre eigene ersetzen, sodass Sie keine künstlichen Wrapper einführen müssen, nur um dem Test-Tool zu entsprechen.

118
gbjbaanb

Ist das Schreiben von testbarem Code auch ohne Tests immer noch eine gute Praxis?

Das Wichtigste zuerst: Das Fehlen von Tests ist ein weitaus größeres Problem, als dass Ihr Code testbar ist oder nicht. Wenn Sie keine Komponententests haben, sind Sie mit Ihrem Code/Ihrer Funktion noch nicht fertig.

Aus dem Weg würde ich nicht sagen, dass es wichtig ist, testbaren Code zu schreiben - es ist wichtig, flexibel Code zu schreiben. Unflexibler Code ist schwer zu testen, daher gibt es dort viele Überschneidungen im Ansatz und wie die Leute ihn nennen.

Für mich gibt es beim Schreiben von Code immer eine Reihe von Prioritäten:

  1. Lass es funktionieren - Wenn der Code nicht das tut, was er tun muss, ist er wertlos.
  2. Machen Sie es wartbar - Wenn der Code nicht wartbar ist, funktioniert er schnell nicht mehr.
  3. Machen Sie es flexibel - Wenn der Code nicht flexibel ist, funktioniert er nicht mehr, wenn das Geschäft unweigerlich vorbeikommt und Sie gefragt werden, ob der Code XYZ ausführen kann.
  4. Mach es schnell - jenseits eines akzeptablen Basisniveaus ist Leistung nur Soße.

Unit-Tests helfen bei der Wartbarkeit des Codes, jedoch nur bis zu einem gewissen Punkt. Wenn Sie den Code weniger lesbar oder anfälliger machen, damit die Komponententests funktionieren, wird dies kontraproduktiv. "Testbarer Code" ist im Allgemeinen flexibler Code, das ist also gut, aber nicht so wichtig wie Funktionalität oder Wartbarkeit. Für so etwas wie die aktuelle Zeit ist es gut, dies flexibel zu machen, aber es schadet der Wartbarkeit, indem es die richtige Verwendung des Codes schwieriger und komplexer macht. Da die Wartbarkeit wichtiger ist, werde ich mich normalerweise dem einfacheren Ansatz zuwenden, auch wenn er weniger testbar ist.

69
Telastyn

Ja, es ist eine gute Praxis. Der Grund ist, dass die Testbarkeit nicht für Tests gedacht ist. Es dient der Klarheit und Verständlichkeit, die es mit sich bringt.

Niemand kümmert sich um die Tests selbst. Es ist eine traurige Tatsache im Leben, dass wir große Regressionstestsuiten benötigen, weil wir nicht brillant genug sind, um perfekten Code zu schreiben, ohne ständig unseren Stand zu überprüfen. Wenn wir könnten, wäre das Konzept der Tests unbekannt, und all dies wäre kein Problem. Ich wünschte, ich könnte. Die Erfahrung hat jedoch gezeigt, dass fast alle von uns dies nicht können. Daher sind Tests, die unseren Code abdecken, eine gute Sache, auch wenn sie Zeit für das Schreiben von Geschäftscode kosten.

Wie verbessern Tests unseren Geschäftscode unabhängig vom Test selbst? Indem wir gezwungen werden, unsere Funktionalität in Einheiten zu unterteilen, deren Richtigkeit leicht nachgewiesen werden kann. Diese Einheiten sind auch leichter zu finden als diejenigen, zu deren Schreiben wir sonst versucht wären.

Ihr Zeitbeispiel ist ein guter Punkt. Solange Sie nur eine Funktion haben, die die aktuelle Zeit zurückgibt, denken Sie vielleicht, dass es keinen Sinn macht, sie programmierbar zu machen. Wie schwer kann es sein, das richtig zu machen? Aber zwangsläufig wird Ihr Programm diese Funktion in anderem Code verwenden, und Sie möchten auf jeden Fall testen, dass Code unter verschiedenen Bedingungen, auch zu verschiedenen Zeiten. Daher ist es eine gute Idee, die Zeit zu manipulieren, zu der Ihre Funktion zurückkehrt - nicht weil Sie Ihrem einzeiligen Aufruf von currentMillis() misstrauen, sondern weil Sie den überprüfen müssen. Anrufer dieses Anrufs unter kontrollierten Umständen. Sie sehen also, dass es nützlich ist, Code testbar zu machen, auch wenn er für sich genommen nicht so viel Aufmerksamkeit zu verdienen scheint.

51
Kilian Foth

Irgendwann muss der Wert initialisiert werden, und warum nicht dem Verbrauch am nächsten?

Möglicherweise müssen Sie diesen Code mit einem anderen Wert als dem intern generierten wiederverwenden. Die Möglichkeit, den Wert einzufügen, den Sie als Parameter verwenden möchten, stellt sicher, dass Sie diese Werte zu jeder beliebigen Zeit generieren können, nicht nur "jetzt" (wobei "jetzt" bedeutet, wenn Sie den Code aufrufen).

Um Code effektiv testbar zu machen, muss Code erstellt werden, der (von Anfang an) in zwei verschiedenen Szenarien (Produktion und Test) verwendet werden kann.

Obwohl Sie argumentieren können, dass es keinen Anreiz gibt, den Code ohne Tests testbar zu machen, ist das Schreiben von wiederverwendbarem Code von großem Vorteil, und beide sind Synonyme.

Außerdem besteht der Zweck der Methode in meinem Kopf darin, einen Wert basierend auf der aktuellen Zeit zurückzugeben, indem Sie ihn zu einem Parameter machen, den Sie implizieren, dass dieser Zweck geändert werden kann/sollte.

Sie könnten auch argumentieren, dass der Zweck dieser Methode darin besteht, einen Wert basierend auf einem Zeitwert zurückzugeben, und Sie benötigen ihn, um diesen Wert basierend auf "jetzt" zu generieren. Eine davon ist flexibler, und wenn Sie sich daran gewöhnen, diese Variante mit der Zeit auszuwählen, steigt Ihre Rate der Wiederverwendung von Code.

12
utnapistim

Es mag albern erscheinen, es so zu sagen, aber wenn Sie Ihren Code testen möchten, ist es besser, testbaren Code zu schreiben. Du fragst:

Irgendwann muss der Wert initialisiert werden, und warum nicht dem Verbrauch am nächsten?

Gerade weil in dem Beispiel, auf das Sie sich beziehen, dieser Code nicht testbar ist. Es sei denn, Sie führen nur eine Teilmenge Ihrer Tests zu unterschiedlichen Tageszeiten aus. Oder Sie setzen die Systemuhr zurück. Oder eine andere Problemumgehung. All dies ist schlimmer, als nur Ihren Code flexibel zu gestalten.

Diese kleine Methode ist nicht nur unflexibel, sondern hat auch zwei Verantwortlichkeiten: (1) Abrufen der Systemzeit und (2) Zurückgeben eines darauf basierenden Werts.

public static string GetTimeOfDay()
{
    DateTime time = DateTime.Now;
    if (time.Hour >= 0 && time.Hour < 6)
    {
        return "Night";
    }
    if (time.Hour >= 6 && time.Hour < 12)
    {
        return "Morning";
    }
    if (time.Hour >= 12 && time.Hour < 18)
    {
        return "Afternoon";
    }
    return "Evening";
}

Es ist sinnvoll, die Verantwortlichkeiten weiter aufzuschlüsseln, damit der Teil außerhalb Ihrer Kontrolle liegt (DateTime.Now) hat den geringsten Einfluss auf den Rest Ihres Codes. Dies vereinfacht den obigen Code und hat den Nebeneffekt, dass er systematisch getestet werden kann.

10
Eric King

Es hat sicherlich Kosten, aber einige Entwickler sind es so gewohnt, es zu bezahlen, dass sie vergessen haben, dass die Kosten da sind. In Ihrem Beispiel haben Sie jetzt zwei Einheiten anstelle von einer, Sie haben den aufrufenden Code benötigt, um eine zusätzliche Abhängigkeit zu initialisieren und zu verwalten, und während GetTimeOfDay besser testbar ist, sind Sie gleich wieder im selben Boot und testen Ihre neues IDateTimeProvider. Es ist nur so, dass bei guten Tests die Vorteile normalerweise die Kosten überwiegen.

Bis zu einem gewissen Grad ermutigt Sie das Schreiben von testbarem Code dazu, Ihren Code auf eine wartbarere Art und Weise zu gestalten. Der neue Abhängigkeitsverwaltungscode ist ärgerlich, daher sollten Sie alle zeitabhängigen Funktionen nach Möglichkeit zusammenfassen. Dies kann dazu beitragen, Fehler zu verringern und zu beheben, z. B. wenn Sie eine Seite direkt an einer Zeitgrenze laden und einige Elemente mit der Vorher-Zeit und andere mit der Nachher-Zeit rendern. Es kann auch Ihr Programm beschleunigen, indem wiederholte Systemaufrufe vermieden werden, um die aktuelle Uhrzeit abzurufen.

Natürlich hängen diese architektonischen Verbesserungen stark davon ab, dass jemand die Chancen erkennt und umsetzt. Eine der größten Gefahren einer so starken Konzentration auf Einheiten besteht darin, das Gesamtbild aus den Augen zu verlieren.

Mit vielen Unit-Test-Frameworks können Sie ein Mock-Objekt zur Laufzeit von Affen patchen, sodass Sie die Vorteile der Testbarkeit ohne all das Durcheinander nutzen können. Ich habe es sogar in C++ gesehen. Untersuchen Sie diese Fähigkeit in Situationen, in denen es so aussieht, als ob sich die Kosten für die Testbarkeit nicht lohnen.

9
Karl Bielefeldt

Es ist möglich, dass nicht jedes Merkmal, das zur Testbarkeit beiträgt, außerhalb des Kontextes der Testbarkeit wünschenswert ist - ich habe beispielsweise Probleme, eine nicht testbezogene Begründung für den von Ihnen angegebenen Zeitparameter zu finden -, aber im Großen und Ganzen die Merkmale, die zur Testbarkeit beitragen tragen auch zu gutem Code bei, unabhängig von der Testbarkeit.

Testbarer Code ist im Großen und Ganzen formbarer Code. Es ist in kleinen, diskreten, zusammenhängenden Stücken, so dass einzelne Bits zur Wiederverwendung aufgerufen werden können. Es ist gut organisiert und gut benannt (um einige Funktionen testen zu können, widmen Sie der Benennung mehr Aufmerksamkeit. Wenn Sie keine Tests schreiben würden, wäre der Name für eine Einwegfunktion weniger wichtig). Es ist in der Regel parametrischer (wie Ihr Zeitbeispiel) und kann daher auch aus anderen Kontexten als dem ursprünglich vorgesehenen Zweck verwendet werden. Es ist trocken, also weniger überladen und leichter zu verstehen.

Ja. Es wird empfohlen, testbaren Code zu schreiben, auch unabhängig vom Testen.

8
Carl Manaster

Das Schreiben von testbarem Code ist wichtig, wenn Sie beweisen möchten, dass Ihr Code tatsächlich funktioniert.

Ich stimme eher den negativen Ansichten zu, Ihren Code in abscheuliche Verzerrungen zu verwandeln, nur um ihn an ein bestimmtes Test-Framework anzupassen.

Auf der anderen Seite musste sich jeder hier irgendwann mit dieser 1.000 Zeilen langen magischen Funktion auseinandersetzen, die nur abscheulich zu bewältigen ist und praktisch nicht berührt werden kann, ohne eine oder mehrere dunkle, nicht offensichtliche Abhängigkeiten irgendwo anders (oder irgendwo in sich selbst, wo die Abhängigkeit kaum zu visualisieren ist) und per Definition nicht testbar sind. Die Vorstellung (was nicht unbegründet ist), dass Test-Frameworks überstrapaziert sind, sollte meiner Meinung nach nicht als kostenlose Lizenz zum Schreiben von nicht testbarem Code von schlechter Qualität angesehen werden.

Testgetriebene Entwicklungsideale neigen dazu, Sie zum Beispiel dazu zu bringen, Verfahren mit Einzelverantwortung zu schreiben, und das ist definitiv eine gute Sache. Persönlich sage ich: Kaufen Sie sich in eine einzige Verantwortung, eine einzige Quelle der Wahrheit, einen kontrollierten Umfang (keine verdammten globalen Variablen) und halten Sie spröde Abhängigkeiten auf ein Minimum, und Ihr Code wird testbar sein. Mit einem bestimmten Test-Framework testbar? Wer weiß. Aber dann ist es vielleicht das Test-Framework, das sich an guten Code anpassen muss und nicht umgekehrt.

Aber nur um klar zu sein, Code, der so klug oder so lang und/oder voneinander abhängig ist, dass er von einem anderen Menschen nicht leicht verstanden wird, ist kein guter Code. Zufälligerweise ist es auch kein Code, der leicht getestet werden kann.

Ist testbar Code besser Code?

Ich weiß es nicht, vielleicht auch nicht. Die Leute hier haben einige gültige Punkte.

Aber ich glaube, dass besser Code auch testbar Code ist.

nd Wenn Sie über seriöse Software für ernsthafte Zwecke sprechen, ist der Versand von nicht getestetem Code nicht die verantwortungsvollste Sache, die Sie mit dem Geld Ihres Arbeitgebers oder Ihrer Kunden tun könnten.

Es ist auch wahr, dass einige Codes strengere Tests erfordern als andere, und es ist ein wenig albern, etwas anderes vorzutäuschen. Wie wäre es, wenn Sie ein Astronaut im Space Shuttle gewesen wären, wenn das Menüsystem, das Sie mit den lebenswichtigen Systemen im Shuttle verbunden hat, nicht getestet worden wäre? Oder ein Mitarbeiter eines Kernkraftwerks, in dem die Softwaresysteme zur Überwachung der Temperatur im Reaktor nicht getestet wurden? Erfordert andererseits ein bisschen Code, der einen einfachen schreibgeschützten Bericht generiert, einen Containerwagen voller Dokumentation und tausend Komponententests? Ich hoffe sicher nicht. Ich sage nur ...

8
Craig

Für mich scheint es jedoch übertrieben, die Zeit als Argument zu verwenden.

Sie haben Recht, und mit Spott können Sie den Code testbar machen und Vermeiden Sie es, die Zeit zu vertreiben (Wortspielabsicht undefiniert). Beispielcode:

def time_of_day():
    return datetime.datetime.utcnow().strftime('%H:%M:%S')

Angenommen, Sie möchten testen, was während einer Schaltsekunde passiert. Wie Sie sagen, um dies zu testen, müssten Sie den (Produktions-) Code ändern:

def time_of_day(now=None):
    now = now if now is not None else datetime.datetime.utcnow()
    return now.strftime('%H:%M:%S')

Wenn Python Schaltsekunden unterstützt würde der Testcode folgendermaßen aussehen:

def test_handle_leap_second(self):
    actual = time_of_day(
        now=datetime.datetime(year=2015, month=6, day=30, hour=23, minute=59, second=60)
    expected = '23:59:60'
    self.assertEquals(actual, expected)

Sie können dies testen, aber der Code ist komplexer als nötig und die Tests immer noch können den Codezweig, den die meisten Produktionscodes verwenden, nicht zuverlässig ausführen (dh keinen Wert für übergeben now). Sie umgehen dies, indem Sie ein mock verwenden. Ausgehend vom ursprünglichen Produktionscode:

def time_of_day():
    return datetime.datetime.utcnow().strftime('%H:%M:%S')

Testcode:

@unittest.patch('datetime.datetime.utcnow')
def test_handle_leap_second(self, utcnow_mock):
    utcnow_mock.return_value = datetime.datetime(
        year=2015, month=6, day=30, hour=23, minute=59, second=60)
    actual = time_of_day()
    expected = '23:59:60'
    self.assertEquals(actual, expected)

Dies bietet mehrere Vorteile:

  • Sie testen time_of_day unabhängig seiner Abhängigkeiten.
  • Sie testen den gleichen Codepfad als Produktionscode.
  • Der Produktionscode ist so einfach wie möglich.

Nebenbei bemerkt ist zu hoffen, dass zukünftige spöttische Frameworks solche Dinge einfacher machen werden. Da Sie beispielsweise die verspottete Funktion als Zeichenfolge bezeichnen müssen, können IDEs sie nicht einfach automatisch ändern, wenn time_of_day verwendet für die Zeit eine andere Quelle.

5
l0b0

Eine Eigenschaft von gut geschriebenem Code ist, dass er robust gegen Änderungen ist. Das heißt, wenn eine Anforderungsänderung eintritt, sollte die Änderung des Codes proportional sein. Dies ist ein Ideal (und wird nicht immer erreicht), aber das Schreiben von testbarem Code hilft uns, diesem Ziel näher zu kommen.

Warum hilft es uns näher zu kommen? In der Produktion arbeitet unser Code innerhalb der Produktionsumgebung, einschließlich der Integration und Interaktion mit all unserem anderen Code. In Unit-Tests fegen wir einen Großteil dieser Umgebung weg. Unser Code ist jetzt robust gegenüber Änderungen , da Tests eine Änderung sind . Wir verwenden die Einheiten auf unterschiedliche Weise, mit unterschiedlichen Eingaben (Verspottungen, schlechte Eingaben, die möglicherweise nie tatsächlich übergeben werden usw.), als wir sie in der Produktion verwenden würden.

Dies bereitet unseren Code auf den Tag vor, an dem Änderungen in unserem System vorgenommen werden. Angenommen, unsere Zeitberechnung muss basierend auf einer Zeitzone eine andere Zeit in Anspruch nehmen. Jetzt haben wir die Möglichkeit, in dieser Zeit zu vergehen und müssen keine Änderungen am Code vornehmen. Wenn wir keine Zeit vergehen lassen und die aktuelle Zeit verwenden möchten, können wir einfach ein Standardargument verwenden. Unser Code ist robust gegen Änderungen weil er testbar ist.

4
cbojar

Nach meiner Erfahrung ist eine der wichtigsten und weitreichendsten Entscheidungen, die Sie beim Erstellen eines Programms treffen, , wie Sie den Code in Einheiten aufteilen (wobei "Einheiten" wird im weitesten Sinne verwendet). Wenn Sie eine klassenbasierte Sprache OO) verwenden, müssen Sie alle internen Mechanismen, die zum Implementieren des Programms verwendet werden, in eine bestimmte Anzahl von Klassen aufteilen. Anschließend müssen Sie den Code jeder Klasse in einige Klassen aufteilen Anzahl der Methoden. In einigen Sprachen haben Sie die Wahl, wie Sie Ihren Code in Funktionen aufteilen möchten. Oder wenn Sie die Sache SOA] ausführen, müssen Sie entscheiden, wie viele Dienste Sie erstellen und was gehen wird in jeden Dienst.

Die von Ihnen gewählte Aufteilung hat enorme Auswirkungen auf den gesamten Prozess. Gute Entscheidungen erleichtern das Schreiben des Codes und führen zu weniger Fehlern (noch bevor Sie mit dem Testen und Debuggen beginnen). Sie erleichtern das Ändern und Warten. Interessanterweise stellt sich heraus, dass es normalerweise auch einfacher ist, test als eine schlechte, sobald Sie eine gute Aufschlüsselung gefunden haben.

Warum ist das so? Ich glaube nicht, dass ich alle Gründe verstehen und erklären kann. Ein Grund ist jedoch, dass eine gute Aufteilung immer die Wahl einer moderaten "Korngröße" für Implementierungseinheiten bedeutet. Sie möchten nicht zu viel Funktionalität und zu viel Logik in eine einzelne Klasse/Methode/Funktion/Modul/etc. Dies erleichtert das Lesen und Schreiben Ihres Codes, erleichtert aber auch das Testen.

Es ist aber nicht nur das. Ein gutes internes Design bedeutet, dass das erwartete Verhalten (Ein-/Ausgänge/usw.) jeder Implementierungseinheit klar und präzise definiert werden kann. Dies ist wichtig zum Testen. Ein gutes Design bedeutet normalerweise, dass jede Implementierungseinheit eine moderate Anzahl von Abhängigkeiten von den anderen aufweist. Das erleichtert Ihren Lesern das Lesen und Verstehen Ihres Codes, erleichtert aber auch das Testen. Die Gründe gehen weiter; Vielleicht können andere mehr Gründe formulieren, die ich nicht kann.

In Bezug auf das Beispiel in Ihrer Frage denke ich nicht, dass "gutes Code-Design" gleichbedeutend ist mit der Aussage, dass alle externen Abhängigkeiten (wie eine Abhängigkeit von der Systemuhr) immer "injiziert" werden sollten. Das mag eine gute Idee sein, aber es ist ein anderes Thema als das, was ich hier beschreibe, und ich werde nicht auf seine Vor- und Nachteile eingehen.

Selbst wenn Sie Systemfunktionen direkt aufrufen, die die aktuelle Uhrzeit zurückgeben, auf das Dateisystem reagieren usw., bedeutet dies nicht, dass Sie Ihren Code nicht isoliert testen können. Der Trick besteht darin, eine spezielle Version der Standardbibliotheken zu verwenden, mit der Sie die Rückgabewerte von Systemfunktionen fälschen können. Ich habe noch nie gesehen, dass andere diese Technik erwähnen, aber es ist ziemlich einfach, mit vielen Sprachen und Entwicklungsplattformen umzugehen. (Hoffentlich ist Ihre Sprachlaufzeit Open Source und einfach zu erstellen. Wenn die Ausführung Ihres Codes einen Verknüpfungsschritt umfasst, ist es hoffentlich auch einfach zu steuern, mit welchen Bibliotheken er verknüpft ist.)

Zusammenfassend ist testbarer Code nicht unbedingt "guter" Code, aber "guter" Code ist normalerweise testbar.

4
Alex D

Wenn Sie mit SOLIDEN Prinzipien arbeiten, sind Sie auf der guten Seite, besonders wenn Sie dies mit [~ # ~] Kuss [~ #) erweitern. ~] , TROCKEN und YAGNI .

Ein fehlender Punkt für mich ist der Punkt der Komplexität einer Methode. Ist es eine einfache Getter/Setter-Methode? Dann wäre es Zeitverschwendung, nur Tests zu schreiben, um Ihr Test-Framework zu erfüllen.

Wenn es sich um eine komplexere Methode handelt, bei der Sie Daten bearbeiten und sicherstellen möchten, dass sie auch dann funktioniert, wenn Sie die interne Logik ändern müssen, ist dies ein guter Aufruf für eine Testmethode. Oft musste ich nach einigen Tagen/Wochen/Monaten einen Code ändern, und ich war wirklich froh, den Testfall zu haben. Als ich die Methode zum ersten Mal entwickelte, habe ich sie mit der Testmethode getestet und war mir sicher, dass sie funktionieren wird. Nach der Änderung funktionierte mein primärer Testcode immer noch. Ich war mir also sicher, dass meine Änderung keinen alten Code in der Produktion beschädigt hat.

Ein weiterer Aspekt beim Schreiben von Tests besteht darin, anderen Entwicklern die Verwendung Ihrer Methode zu zeigen. Oft sucht ein Entwickler nach einem Beispiel für die Verwendung einer Methode und den Rückgabewert.

Nur mein zwei Cent .

1
BtD