Ich habe die Dokumente von phpunit durchgesehen und bin auf folgendes Zitat gestoßen:
Sie können immer mehr Tests schreiben. Sie werden jedoch schnell feststellen, dass nur ein Bruchteil der Tests, die Sie sich vorstellen können, tatsächlich nützlich sind. Sie möchten Tests schreiben, die fehlschlagen, obwohl Sie glauben, dass sie funktionieren sollten, oder Tests, die erfolgreich sind, obwohl Sie glauben, dass sie fehlschlagen sollten. Eine andere Sichtweise ist das Kosten-Nutzen-Verhältnis. Sie möchten Tests schreiben, die Sie mit Informationen zurückzahlen. - Reiches Gamma
Ich habe mich gefragt. Wie bestimmen Sie, was einen Komponententest nützlicher macht als einen anderen, abgesehen davon, was in diesem Zitat über Kosten / Nutzen angegeben ist? Wie entscheiden Sie, für welchen Teil Ihres Codes Sie Komponententests erstellen? Ich frage das, weil ein anderes dieser Zitate auch sagte:
Wenn es also nicht um Testen geht, worum geht es dann? Es geht darum, herauszufinden, was Sie versuchen, bevor Sie halb gespannt davonlaufen, um es zu versuchen. Sie schreiben eine Spezifikation, die einen kleinen Aspekt des Verhaltens in einer präzisen, eindeutigen und ausführbaren Form festhält. So einfach ist das. Heißt das, Sie schreiben Tests? Nein. Das bedeutet, Sie schreiben Spezifikationen, was Ihr Code tun muss. Dies bedeutet, dass Sie das Verhalten Ihres Codes im Voraus festlegen. Aber nicht weit vor der Zeit. In der Tat ist es am besten, kurz bevor Sie den Code schreiben, da Sie dann so viele Informationen zur Hand haben, wie Sie bis dahin wollen. Wie bei gut gemachtem TDD arbeiten Sie in winzigen Schritten ... indem Sie jeweils einen kleinen Aspekt des Verhaltens festlegen und dann implementieren. Wenn Sie feststellen, dass es nur darum geht, Verhalten zu spezifizieren und keine Tests zu schreiben, Ihr Standpunkt verschiebt sich. Plötzlich ist die Idee, für jede Ihrer Produktionsklassen eine Testklasse zu haben, lächerlich einschränkend. Und der Gedanke, jede Ihrer Methoden mit einer eigenen Testmethode (in einer 1: 1-Beziehung) zu testen, wird lächerlich sein. - Dave Astels
Der wichtige Teil davon ist
* Und der Gedanke, jede Ihrer Methoden mit einer eigenen Testmethode (in einer 1: 1-Beziehung) zu testen, ist lächerlich. *
Wenn es also lächerlich ist, für jede Methode einen Test zu erstellen, wie / wann haben Sie dann ausgewählt, wofür Sie Tests schreiben?
quelle
Antworten:
Wie viele Tests pro Methode?
Nun, das theoretische und höchst unpraktische Maximum ist die N-Pfad-Komplexität (vorausgesetzt, die Tests decken alle verschiedene Wege durch den Code ab;)). Das Minimum ist EINS !. Gemäß der öffentlichen Methode testet er keine Implementierungsdetails, sondern nur das externe Verhalten einer Klasse (Rückgabewerte und Aufrufen anderer Objekte).
Sie zitieren:
und dann fragen:
Aber ich denke, Sie haben den Autor hier falsch verstanden:
Die Idee,
one test method
Per zu haben,one method in the class to test
nennt der Autor "lächerlich".(Zumindest für mich) Es geht nicht um "weniger", es geht um "mehr"
Lassen Sie mich so umformulieren, als hätte ich ihn verstanden:
Und der Gedanke, jede Ihrer Methoden mit NUR EINER METHODE (einer eigenen Testmethode in einer 1: 1-Beziehung) zu testen, wird lächerlich sein.
So zitieren Sie Ihr Angebot erneut:
Wenn Sie TDD üben, denken Sie nicht :
Ich habe eine Methode
calculateX($a, $b);
und es braucht einen TesttestCalculcateX
, der ALLES über die Methode testet.Was TDD Ihnen sagt, ist darüber nachzudenken, was Ihr Code tun sollte :
Ich muss den größeren von zwei Werten berechnen ( erster Testfall! ), Aber wenn $ a kleiner als Null ist, sollte es einen Fehler erzeugen ( zweiter Testfall! ) Und wenn $ b kleiner als Null ist, sollte es ... ( dritter Testfall! ) und so weiter.
Sie möchten Verhalten testen, nicht nur einzelne Methoden ohne Kontext.
Auf diese Weise erhalten Sie eine Testsuite, die Dokumentation für Ihren Code ist und WIRKLICH erklärt, was von ihm erwartet wird, vielleicht sogar warum :)
Wie entscheiden Sie, für welchen Teil Ihres Codes Sie Komponententests erstellen?
Nun, alles, was im Endlager oder irgendwo in der Nähe der Produktion landet, muss getestet werden. Ich glaube nicht, dass der Autor Ihrer Zitate damit nicht einverstanden wäre, wie ich oben dargelegt habe.
Wenn Sie keinen Test dafür haben, wird es viel schwieriger (teurer), den Code zu ändern, besonders wenn Sie die Änderung nicht vornehmen.
TDD ist eine Möglichkeit, um sicherzustellen, dass Sie Tests für ALLES haben, aber solange Sie die Tests schreiben, ist es in Ordnung. Normalerweise hilft es, sie am selben Tag zu schreiben, da Sie es später nicht tun werden, oder? :)
Antwort auf Kommentare:
Nun, diese Methoden können drei Dinge aufrufen:
Öffentliche Methoden anderer Klassen
Wir können andere Klassen verspotten, also haben wir dort den Status definiert. Wir haben die Kontrolle über den Kontext, so dass dies kein Problem ist.
* Geschützte oder private Methoden auf dem gleichen *
Alles, was nicht Teil der öffentlichen API einer Klasse ist, wird normalerweise nicht direkt getestet.
Sie möchten das Verhalten und nicht die Implementierung testen, und wenn eine Klasse alles tut, funktioniert dies in einer großen öffentlichen Methode oder in vielen kleineren geschützten Methoden, die aufgerufen werden, in der Implementierung . Sie möchten in der Lage sein, diese geschützten Methoden ZU ÄNDERN, OHNE Ihre Tests zu berühren. Denn Ihre Tests brechen ab, wenn Ihr Code das Verhalten ändert! Dafür sind deine Tests da, um dir zu sagen, wann du etwas kaputt machst :)
Öffentliche Methoden für dieselbe Klasse
Das kommt nicht sehr oft vor, oder? Und wenn es wie im folgenden Beispiel aussieht, gibt es ein paar Möglichkeiten, damit umzugehen:
Dass die Setter existieren und nicht Teil der Signatur der Execute-Methode sind, ist ein anderes Thema;)
Was wir hier testen können, ist, ob Executes explodieren, wenn wir die falschen Werte einstellen. Das
setBla
löst eine Ausnahme aus, wenn Sie eine Zeichenfolge übergeben, die separat getestet werden kann. Wenn Sie jedoch testen möchten, dass diese beiden zulässigen Werte (12 und 14) nicht ZUSAMMEN (aus welchem Grund auch immer) funktionieren, ist dies nur ein Testfall.Wenn Sie eine "gute" Testsuite wollen, können Sie in PHP vielleicht (!) Eine
@covers Stuff::execute
Anmerkung hinzufügen , um sicherzustellen, dass Sie nur Code-Coverage für diese Methode generieren, und die anderen Dinge, die gerade eingerichtet werden, müssen separat getestet werden (noch einmal, wenn Du willst das).Der Punkt ist also: Vielleicht müssen Sie zuerst einen Teil der umgebenden Welt erstellen, aber Sie sollten in der Lage sein, aussagekräftige Testfälle zu schreiben, die normalerweise nur eine oder vielleicht zwei reale Funktionen umfassen (Setter zählen hier nicht). Der Rest kann verspottet oder zuerst getestet und dann als Referenz herangezogen werden (siehe
@depends
).* Hinweis: Die Frage wurde von SO migriert und betraf ursprünglich PHP / PHPUnit. Aus diesem Grund stammen der Beispielcode und die Referenzen aus der PHP-Welt. Ich denke, dies gilt auch für andere Sprachen, da sich phpunit nicht wesentlich von anderen xUnit unterscheidet Testen von Frameworks.
quelle
Testen und Unit-Testen sind nicht dasselbe. Unit Testing ist eine sehr wichtige und interessante Untergruppe von Tests insgesamt. Ich würde behaupten, dass der Schwerpunkt des Unit-Testings uns dazu bringt, über diese Art des Testens in einer Weise nachzudenken, die den obigen Zitaten etwas widerspricht.
Erstens, wenn wir TDD oder sogar DTH befolgen (dh in enger Harmonie entwickeln und testen), verwenden wir die Tests, die wir schreiben, um unser Design richtig zu machen. Wenn wir über Eckfälle nachdenken und entsprechende Tests schreiben, vermeiden wir, dass die Fehler überhaupt erst auftreten. Wir schreiben also Tests, die wir für bestanden halten (OK, gleich zu Beginn des TDD, sie schlagen fehl, aber das ist nur ein Bestellungsartefakt, wenn Der Code ist fertig, wir erwarten, dass sie bestanden werden, und die meisten tun dies, weil Sie über den Code nachgedacht haben.
Zweitens kommen die Unit Tests erst richtig zur Geltung, wenn wir überarbeiten. Wir ändern unsere Implementierung, erwarten jedoch, dass die Antworten gleich bleiben - der Unit-Test schützt uns vor dem Bruch unseres Schnittstellenvertrags. Also noch einmal, wir erwarten, dass die Tests bestehen.
Dies bedeutet, dass wir für unsere öffentliche Schnittstelle, die vermutlich stabil ist, eine eindeutige Rückverfolgbarkeit benötigen, damit wir sehen können, dass jede öffentliche Methode getestet wird.
Um Ihre explizite Frage zu beantworten: Unit Test für öffentliche Schnittstelle haben Wert.
bearbeitet im Antwortkommentar:
Private Methoden testen? Ja, wir sollten, aber wenn wir etwas nicht testen müssen, würde ich hier Kompromisse eingehen. Wenn die öffentlichen Methoden funktionieren, können dann diese Fehler im privaten Bereich so wichtig sein? Pragmatisch gesehen ist die Abwanderung im privaten Bereich eher selten, Sie arbeiten hart daran, Ihre öffentliche Schnittstelle zu pflegen, aber wenn sich die Dinge ändern, auf die Sie angewiesen sind, können sich die privaten Dinge ändern. Irgendwann stellen wir möglicherweise fest, dass die internen Tests sehr aufwändig sind. Ist diese Anstrengung sinnvoll?
quelle
Unit-Tests sollten Teil einer umfassenderen Teststrategie sein. Ich folge diesen Grundsätzen bei der Auswahl der zu schreibenden Testarten und wann:
Konzentrieren Sie sich auf das Schreiben von End-to-End-Tests. Sie decken mehr Code pro Test als bei Unit-Tests ab und erhalten so mehr Testknall für das Geld. Machen Sie diese zur vollautomatischen Validierung Ihres gesamten Systems.
Schreiben Sie Unit-Tests zu Nuggets komplizierter Logik. Komponententests sind in Situationen, in denen End-to-End-Tests für eine angemessene Codeabdeckung schwer zu debuggen oder schwer zu schreiben sind, ihr Gewicht zu verdienen.
Warten Sie, bis die API, gegen die Sie testen, stabil ist , um einen der beiden Testtypen zu schreiben. Sie möchten vermeiden, dass sowohl Ihre Implementierung als auch Ihre Tests überarbeitet werden müssen.
Rob Ashton hat einen guten Artikel zu diesem Thema, aus dem ich mich stark gemacht habe, um die oben genannten Prinzipien zu artikulieren.
quelle
Ich tendiere dazu, einen anderen Ansatz zum Testen von Einheiten zu verfolgen, der anscheinend gut funktioniert. Anstatt einen Unit-Test als "Testen eines Verhaltens" zu betrachten, betrachte ich ihn eher als "eine Spezifikation, der mein Code folgen muss". Auf diese Weise können Sie im Grunde deklarieren, dass sich ein Objekt auf eine bestimmte Weise verhalten soll, und vorausgesetzt, dass Sie an anderer Stelle in Ihrem Programm davon ausgehen, dass es relativ fehlerfrei ist.
Wenn Sie eine öffentliche API schreiben, ist dies äußerst wertvoll. Sie werden jedoch auch immer eine gute Dosis von End-to-End-Integrationstests benötigen, da sich eine Annäherung an eine 100% -ige Abdeckung von Komponententests normalerweise nicht lohnt und Dinge übersehen werden, die die meisten nach Komponententestmethoden als "nicht testbar" erachten (Verspotten, usw)
quelle