Dienstag, 14. September 2010

Is F.I.R.S.T Spooky?

Der Test F.I.R.S.T Ansatz polarisiert. Die Anhänger von Test F.I.R.S.T sprechen von der Verwendersicht, Fakes, Test Fixtures, Isolation, loser Kopplung und Wiederholbarkeit. Tatsächlich sind das alles Eigenschaften von Unit-Tests, dem Treiber für Test F.I.R.S.T. Die Gegner dieses Ansatzes sprechen von nicht automatisierbaren GUI-Tests, externen Systemen, die zu berücksichtigen sind, der Komplexität der zu implementierenden Funktionalität, Seiteneffekten und der braunen Masse des Quellcodes.

Bei Greenfield-Projekten ist die Polarisierung des Ansatzes weniger stark als bei Brownfield-Projekten. Das Problem bei Brownfield-Projekten ist häufig, dass der Quellcode nicht testgetrieben entwickelt wurde und deshalb keine isolierten Schnittstellen für die Programmierung von Unit-Tests vorliegen. In diesem Fall ist die Testbarkeit herzustellen, eine mehr oder weniger große Hürde für den Entwickler. Grundsätzlich spielt der Zeitrahmen des Projektes  eine Rolle. Der Eindruck entsteht, dass die testgetriebene Weiterentwicklung eines Brownfield-Projektes durch das vorzunehmende Refactoring zu aufwendig sei. Der Zeitrahmen könnte wackeln. Sicherlich ist in Brownfield-Projekten oftmals der Fall, dass die Abhängigkeiten im Quellcode groß sind, sodass aufgrund des Aufwandes kein umfangreiches Refactoring zur Herstellung der Testbarkeit  geplant ist. Stellt man die Testbarkeit allerdings nicht her, begibt man sich in die Gefahr, sich im Netz der Abhängigkeiten zu verfangen und durch Seiteneffekte bei der Weiterentwicklung stark behindert zu werden.

Die Bedenken gegen den Einsatz von Unit-Tests zur Neu- und Weiterentwicklung einer Software sind  unterschiedlich stark ausgeprägt, sodass der Ansatz manchmal schon früh im Keim erstickt wird. Sicherlich sind GUIs nur schwierig mit diesem Ansatz zu implementieren. Doch wurde die GUI nach dem Model View Controller (MVC) Pattern programmiert, lässt sich das Modell testgetrieben implementieren. Unit-Tests erfordern, dass kleine isolierte testbare Einheiten, die entkoppelt voneinander sind, entstehen. Wie der Verwender diese Einheiten sieht, ist wesentlich für die Strukturierung der Tests. Die Verwendersicht fördert die Benutzerfreundlichkeit der gerade entstehenden Anwendung und wirkt sich positiv auf die Lesbarkeit des Quellcodes aus.

Bei der Diskussion des Test F.I.R.S.T Ansatzes erkennt man Relationen zu Design by Contract. Bei beiden Ansätzen denkt man über die Verwender und einen zu erfüllenden Vertrag nach. Der Schluß liegt deshalb nahe, dass alleine das Nachdenken über den Verwender des Quellcodes die Qualität deutlich verbessert. Ein weiteres Qualitätsmerkmal ist die Isolation, die eine hohe Flexibilität in der Weiterentwicklung mit sich bringt ohne weitläufige Seiteneffekte hervorzurufen. Die lose Kopplung fördert die Austauschbarkeit von Komponenten und die Wiederverwendbarkeit. In der Summe eine angenehme Ausgangsposition für die Wartung mit einhergehenden Refactoringmaßnahmen.

Auffällig ist, dass die testgetriebene Entwicklung offensichtlich Zufriedenheit bei Entwicklern hervorruft. Der Grund dafür könnte die Gewissheit sein, ein Stück fehlerfreie Software programmiert zu haben und dies jederzeit mit einem Testlauf beweisen zu können. Man sagt, dass Entwickler die testgetrieben arbeiten früher Feierabend haben, Tests zum Lernen nutzen, bei einer Quellcodebasis zuerst die Tests und dann die API-Dokumentation studieren, den Quellcode per Shortcut von der Entwicklungsumgebung generieren lassen und sich über einen roten Balken genauso wie über einen grünen Balken freuen. Vielleicht sind es auch nur die vielen kleinen Erfolgserlebnisse bei der Programmierung, das Wechselspiel von rot zu grün, die kleinen Schritte, die es nicht erlauben sich zu verlaufen und die Frustration stattfinden zu lassen.

Spooky

Theorie zu F.I.R.S.T

F.I.R.S.T bezeichnet die fünf Eigenschaften von sauberen Unit-Tests, die zu stabilen und qualitativ hochwertigen testgetriebenen Komponenten führen. Bedenke! Unit-Tests sind mit der gleichen Qualität wie der eigentliche Quellcode zu erstellen.
  1. Fast - Tests müssen schnell sein, viele hundert in Sekunden.

  2. Isolated - Tests isolieren Fehler und testen gezielt nur eine Funktionalität. Falls Fehler durch einen Test nicht isoliert werden können, sind kleinere Testeinheiten zu schreiben. Tests hängen nicht voneinander ab.

  3. Repeatable - Tests müssen zu jeder Zeit wiederholbar sein. Wiederholbare Tests sind automatisch ausführbar und dürfen deshalb keine Abhängigkeiten zu externen Services und/oder Ressourcen haben.

  4. Self validating - Testergebnisse haben einen boolschen Wert. Entweder ein Test war erfolgreich oder der Test ist fehlgeschlagen.

  5. Timely - Tests werden zum richtigen Zeitpunkt geschrieben. Bei Test F.I.R.S.T noch bevor der eigentliche Quellcode erstellt wurde.