{"id":354,"date":"2015-06-17T16:15:16","date_gmt":"2015-06-17T14:15:16","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=354"},"modified":"2015-07-04T14:36:31","modified_gmt":"2015-07-04T12:36:31","slug":"vom-testen-getrieben","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/vom-testen-getrieben\/","title":{"rendered":"Vom Testen getrieben"},"content":{"rendered":"<p>Hallo Spa\u00df Coder,<\/p>\n<p>nachdem wir\u00a0in den letzten Artikeln unserer Serie schon einiges zum Thema <a href=\"http:\/\/invidit.de\/blog\/testautomatisierung\/\">Testautomatisierung<\/a> im allgemeinen und <a href=\"http:\/\/invidit.de\/blog\/von-tests-und-komponenten\/\">Unit-Tests<\/a> im speziellen gelernt haben, m\u00f6chten wir heute auf eine besondere Technik\u00a0automatisierter Tests eingehen.<\/p>\n<p>&nbsp;<\/p>\n<h1>Test-Driven-Development<\/h1>\n<p>Beim Test-Driven-Development (abgek\u00fcrzt TDD) geht es darum,\u00a0den automatisierten Test in den Mittelpunkt der Entwicklung zu stellen. Entstanden ist die Idee von Kent Beck,\u00a0der insbesondere Unit-Tests damit im Blick hatte.\u00a0Das Ziel dabei ist es, den Code in kleinen Iterationen zu entwickeln, wobei der Code bei jedem Zyklus folgende\u00a0Stufen durchl\u00e4uft:<\/p>\n<ol>\n<li>Implementieren des Akzeptanztests in Form eines Unit-Tests, der fehlschl\u00e4gt<\/li>\n<li>Implementieren der kleinstm\u00f6glichen L\u00f6sung im Produktionscode<\/li>\n<li>Refaktorisieren des Produktionscodes<\/li>\n<\/ol>\n<p>Diese Zyklen werden so lange mit allen Anforderungen wiederholt, bis die gew\u00fcnschte Funktion vollst\u00e4ndig implementiert ist.<\/p>\n<p>Kent Beck nennt diesen Zyklus <span style=\"color: #ff0000;\">Red<\/span>&#8211;<span style=\"color: #008000;\">Green<\/span>&#8211;<span style=\"color: #3366ff;\">Refactor<\/span>. Zuerst wird ein Unit-Test geschrieben der fehlschl\u00e4gt, also in der IDE <span style=\"color: #ff0000;\">rot<\/span> dargestellt wird. Anschlie\u00dfend wird die Funktion soweit implementiert, dass der Test nicht mehr fehlschl\u00e4gt und somit in der IDE <span style=\"color: #008000;\">gr\u00fcn <\/span>dargestellt wird. Ist die Implementierung des Produktionscodes abgeschlossen, wird ein <span style=\"color: #3366ff;\">Refactoring <\/span>durchgef\u00fchrt, um auch die Qualit\u00e4t des Codes hoch zu halten.<\/p>\n<p>Voraussetzung f\u00fcr den Zyklus ist, dass die wesentlichen Akzeptanztests bereits vor dem Start der Entwicklung formuliert sind.<\/p>\n<p>&nbsp;<\/p>\n<h3>Bewusster Perspektiven-Wechsel<\/h3>\n<p>Martin Fowler macht noch mal sehr deutlich, dass ich als Entwickler in diesem Zyklus zwei verschiedene Perspektiven einnehme, wenn ich Code \u00e4ndere. Martin hat dies anhand von zwei H\u00fcten beschrieben, die ich nacheinander aufsetze. Einerseits implementiere ich die Anforderung und entwickle den Algorithmus oder die Fachlogik. Eben genau so lange, bis meine Tests (wieder) <span style=\"color: #008000;\">gr\u00fcn<\/span> sind. Hierbei erg\u00e4nze ich eine Funktion und trage den ersten Hut. F\u00fcr das <span style=\"color: #3366ff;\">Refactoring<\/span> wechsle ich nun meinen Hut und schaue konzentriert auf die Codestruktur mit der expliziten Absicht, die Funktionsweise des Codes <strong>nicht<\/strong> zu ver\u00e4ndern. Die Tests geben mir dabei Feedback, dieses im Blick zu halten. Solange diese <span style=\"color: #008000;\">gr\u00fcn<\/span> bleiben, habe ich keine (bisher getestete) Funktionsweise ver\u00e4ndert.<\/p>\n<p>Die Idee bei dieser Symbolik ist, dass ich die beiden H\u00fcte nie gleichzeitig aufsetzen kann und daher ganz bewusst den Hut (die Perspektive) wechsle, wenn ich im Code arbeite &#8211; entweder Funktionen erg\u00e4nzen oder den Code umstrukturieren. Diese strikte Trennung unterst\u00fctzt eine strukturierte Arbeitsweise, so dass ich nicht zu viele Dinge auf einmal mache.<\/p>\n<p>&nbsp;<\/p>\n<h1>Was spricht f\u00fcr TDD?<\/h1>\n<p>Durch den einfachen Zyklus von Kent Beck erreichen wir Vieles, was auf den ersten Blick nicht ersichtlich wird.<\/p>\n<p><strong>Sicherstellen von\u00a0Akzeptanzkriterien, statt pr\u00fcfen\u00a0einer Funktion<\/strong><\/p>\n<p>Neben der offensichtlichen Tatsache, dass wir zu jedem unserer Anwendungsf\u00e4lle nach Abschluss der Entwicklung einen Unit-Test haben, sind diese Tests auch relevant. Sie pr\u00fcfen\u00a0nicht eine Funktion, die wir implementiert haben. Vielmehr stellt ein\u00a0so erstellter Test sicher, dass ein durch den Anforderer formuliertes Akzeptanzkriterium erf\u00fcllt wird. Dies erh\u00f6ht deutlich die Qualit\u00e4t des Tests an sich.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Sauberes Interface implementieren<\/strong><\/p>\n<p>Wenn wir zuerst\u00a0den Test schreiben, bevor wir mit der Implementierung des Produktionscodes beginnen,\u00a0werfen wir als Entwickler einen ganz anderen Blick auf die Aufgabenstellung. So schauen wir beim Schreiben von Tests aus Sicht des Aufrufers auf unsere Klasse. Wir \u00fcberlegen uns also: &#8222;Wie w\u00fcrde ich diese Klasse verwenden wollen?&#8220; Daraus ergibt sich fr\u00fch ein sauberes Interface der Methoden der Klasse, noch bevor auch nur eine Zeile Produktionscode geschrieben ist:<\/p>\n<ul>\n<li>Wie\u00a0sollte die Klasse hei\u00dfen?<\/li>\n<li>Welche Methoden brauche ich und wie sollten sie hei\u00dfen?<\/li>\n<li>Welche Parameter \u00fcbergebe ich?<\/li>\n<li>Wie erstelle ich die Instanz der Klasse?<\/li>\n<\/ul>\n<p>All diese Fragen stellen wir uns typischerweise nicht, wenn wir gleich mit der Implementierung beginnen.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Fokussieren auf die Anforderung<\/strong><\/p>\n<p>Ein anderer Aspekt ist die Fokussierung auf die Anforderung. Fangen wir gleich mit dem Produktionscode an, vergraben wir uns oft\u00a0schnell in Details zur Probleml\u00f6sung.\u00a0Dar\u00fcber hinaus versuchen wir die Anforderung h\u00e4ufig gleich ganzheitlich zu l\u00f6sen. Gehen wir stattdessen von den Akzeptanztests aus, erf\u00fcllen\u00a0wir immer genau nur eine Anforderung nach der anderen, l\u00f6sen\u00a0einen Akzeptanztest nach dem anderen.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Refactoring in Fleisch und Blut<\/strong><\/p>\n<p>Das\u00a0Refaktorisieren ist fester Bestandteil\u00a0im\u00a0o.g. Zyklus. Verfolgen wir diesen fokussieren Ansatz, haben wir jeden Teil unseres Produktionscodes nicht nur getestet, sondern hinterlassen den Code auch sofort sauber und ordentlich. Wir erstellen nicht erst einen riesigen Berg Produktionscode, den wir dann nochmal aufr\u00e4umen m\u00fcssen, sondern sorgen\u00a0w\u00e4hrend der gesamten Implementierungsphase f\u00fcr sauberen, gut strukturierten Code.<\/p>\n<p>Sollte es durch eine sp\u00e4ter umgesetzte Anforderung notwendig werden, vorherige Teile neu zu implementieren, ist dieser so gut strukturiert, dass er sich\u00a0leicht umstellen l\u00e4sst&#8230;und getestet ist er ja auch, also Angst vor der Umstellung brauchen wir auch nicht zu haben.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Viele kleine Belohnungen<\/strong><\/p>\n<p>Durch den Zyklus <span style=\"color: #ff0000;\">Red<\/span>&#8211;<span style=\"color: #339966;\">Green<\/span>&#8211;<span style=\"color: #3366ff;\">Refactor<\/span> erfahren wir regelm\u00e4\u00dfig Belohnungen. Der Test ist gr\u00fcn? Cool, wieder was geschafft! Der Code ist sauber refaktorisiert? Klasse, ein Akzeptanzkriterium umgesetzt, auf zum n\u00e4chsten!<\/p>\n<p>Auch wenn dieser Vorteil eher unwichtig klingt, ist er doch nicht zu vernachl\u00e4ssigen. Je besser wir &#8222;drauf&#8220; sind, desto besser ist unsere L\u00f6sung und desto sauberer wird unser Code.<\/p>\n<p>&nbsp;<\/p>\n<h1>Was spricht gegen\u00a0TDD?<\/h1>\n<p><strong>Kosten<\/strong><\/p>\n<p>Auch wenn es sich in er Erz\u00e4hlung einfach anh\u00f6rt, ist eine Eingew\u00f6hnung in das Thema wichtig. Wir\u00a0erl\u00e4utern das sp\u00e4ter nochmal bei unseren Erfahrungen. F\u00fcr ein erfolgreiches\u00a0Test-Driven-Development\u00a0ist also noch mehr Investition notwendig, als ohnehin schon f\u00fcr die <a href=\"http:\/\/invidit.de\/blog\/testautomatisierung\/\">Testautomatisierung<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Akzeptanzkriterien erforderlich<\/strong><\/p>\n<p>TDD funktioniert nur dann, wenn die Akzeptanzkriterien der Anforderung bekannt sind. Nur dann k\u00f6nnen wir die richtigen Tests formulieren und implementieren. Manchmal k\u00f6nnen wir uns selbst im Vorfeld welche \u00fcberlegen, wenn sie nicht im Rahmen\u00a0der Anforderung formuliert wurden.\u00a0<span style=\"line-height: 1.5;\">Immer dann aber, wenn wir gar nicht so genau wissen, was wir erreichen wollen, funktioniert TDD nicht gut. Das ist in der Regel immer dann der Fall, wenn wir was ausprobieren wollen, wenn wir experimentieren.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h1>Unsere Erfahrung mit TDD<\/h1>\n<p>Ganz ehrlich? Test-Driven-Development f\u00fchlt sich komisch an. Einen Test schreiben f\u00fcr Code, den wir noch gar nicht haben? Das geht doch gar nicht! Das war meine (Torsten) erste Reaktion auf das Verfahren. Auch sp\u00e4ter, nachdem ich es einmal ausprobiert hatte, fand ich das Vorgehen irgendwie doof. Ich bin immer wieder in alte\u00a0Verhaltensweisen verfallen. Lieber erst mal den Code schreiben und dann schauen, was man testen kann.<\/p>\n<p>Michael hat mich dann aber bei einigen unserer <a href=\"http:\/\/invidit.de\/blog\/1-1-3\/\">Pair-Programming<\/a>-Sitzungen dazu ermuntert, es doch noch mal auszuprobieren. Und ja, die oben aufgef\u00fchrten Vorteile lassen sich tats\u00e4chlich erreichen. Nach einiger \u00dcbung\u00a0f\u00fchlt sich das Ganze gar nicht mehr so komisch an und ist gar nicht so doof, wie es anfangs erscheint.<\/p>\n<p>Vielmehr ist die Implementierung wesentlich zielgerichteter und der Code der entsteht entspricht viel mehr der Qualit\u00e4t\u00a0die wir uns selbst gesetzt haben. Seitdem versuchen wir TDD so oft wie m\u00f6glich anzuwenden.<\/p>\n<p>&nbsp;<\/p>\n<h1>Zusammenfassung<\/h1>\n<p>TDD hat einige weitere Vorteile gegen\u00fcber dem normalen Unit-Test. Die Testabdeckung und -qualit\u00e4t wird erh\u00f6ht, die Schnittstelle und Struktur eures Codes ist besser, die Arbeit ist fokussierter und macht mehr Spa\u00df.<\/p>\n<p>Ihr habt ein komisches Gef\u00fchl und wisst nicht wie ihr anfangen sollt? Dann habt ihr euch wahrscheinlich noch keine ausreichenden Gedanken \u00fcber die Akzeptanzkriterien der Anforderung gemacht. Oder die Anforderung ist noch zu gro\u00df.<\/p>\n<p>TDD passt hervorragend zur Agilen Softwareentwicklung, in der wir mit kleinen Anforderungen in Form von User-Stories arbeiten. Zu einer vollst\u00e4ndigen User-Story geh\u00f6ren auch Akzeptanzkriterien, die gemeinsam mit dem Product Owner erarbeitet werden. Dies und die generelle Haltung\u00a0in kleinen Iterationen zu arbeiten ist die perfekte Basis f\u00fcr Test-Driven-Development.<\/p>\n<p>Unser Appell an euch: Probiert es aus! Haltet durch, auch wenn es sich am Anfang seltsam anf\u00fchlt. Die unmittelbare Belohnung durch den Zyklus, die h\u00f6here Testabdeckung und der saubere Code\u00a0werden euch gefallen.<\/p>\n<p>&nbsp;<\/p>\n<p>Viel Spa\u00df beim Anwenden.<\/p>\n<p>Eure Spa\u00df-Coder<\/p>\n<p>&nbsp;<\/p>\n<p>Dieser Artikel basiert neben unseren Erfahrungen auf folgenden Quellen:<\/p>\n<ul>\n<li>http:\/\/de.wikipedia.org\/wiki\/Testgetriebene_Entwicklung<\/li>\n<li>Workflows of Refactoring, Martin Fowler OOP 2014 (<a href=\"https:\/\/youtu.be\/vqEg37e4Mkw\">https:\/\/youtu.be\/vqEg37e4Mkw<\/a>)<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df Coder, nachdem wir\u00a0in den letzten Artikeln unserer Serie schon einiges zum Thema Testautomatisierung im allgemeinen und Unit-Tests im speziellen gelernt haben, m\u00f6chten wir heute auf eine besondere Technik\u00a0automatisierter Tests eingehen. &nbsp; Test-Driven-Development Beim Test-Driven-Development (abgek\u00fcrzt TDD) geht es darum,\u00a0den automatisierten Test in den Mittelpunkt der Entwicklung zu stellen. Entstanden ist die Idee von [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":509,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[90],"tags":[88,18,89,69,75],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/354"}],"collection":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=354"}],"version-history":[{"count":9,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/354\/revisions"}],"predecessor-version":[{"id":519,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/354\/revisions\/519"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/509"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}