Um was geht es beim Testen?

BugNeulich stand am .Net Usergroup-Treffen in Regensburg das automatisierte Testen auf der Agenda [1]. Grundsätzlich ein wichtiges Thema, nicht nur für mich, sondern auch für viele andere Softwareentwickler – alleine die hohe Teilnehmerzahl macht dies deutlich. An dieser Stelle direkt ein Dank an den Sprecher Kenny Pflug, er hat das Thema gut dargestellt – auch wenn es die eine oder andere Kritik an dem Beispielprogramm gab ;). Bei dem Vortrag konnte ich einige Dinge dazulernen, beispielsweise nennt sich das, was ich normalerweise als „Testdriven Development“ in der Arbeit vorantreibe, in Wirklichkeit „Behavior Driven Development“. Naja.. ich mache mir halt nicht viel aus Schlagworten 😉

Bei all den Infos und den Diskussionen, welche während des Verlaufs des Vortrags entstanden sind, konnte man erneut beobachten, dass die Erwartungshaltung an automatisierte Tests von Entwickler zu Entwicklung oder besser gesagt von Firma zu Firma anders sind. Nehmen wir als Beispiel die Testpyramide aus nachfolgendem Screenshot (Quelle [2]). Diese wurde auch im besagten Vortrag in vereinfachter Form gezeigt und sagt grundsätzlich aus, dass der Großteil der Programmlogik mittels Unit Tests abgedeckt sein sollte. Die tendenziell aufwändigeren Komponenten-, Integrations- und GUI-Tests sollten jeweils entsprechend weniger werden. Wie gesagt, sollten..

Testpyramide

Selbst der Gefahr hin, dass mich hierfür die meisten Verfechter obiger Testpyramide lynchen werden, stelle ich hier dar, wie diese Test-„Pyramide“ bei mir nicht selten aussieht. Zunächst möchte ich auf einen vorangegangenen Blog-Eintrag verweisen [3], hier habe ich an einem Beispiel gezeigt, wie Komponenten-Tests bei mir typischerweise aussehen. Jeden ist sicher klar, dass das weit vom Konzept des klassischen Unit Test entfernt ist. Der Vorteil ist aber eine hohe Testabdeckung und.. mal ehrlich.. macht es Sinn bei einer 3D-Engine tausende von Funktionen separat zu testen? Viel Spaß beim Refactoring sage ich da nur.. ich habe lange aufgehört zu zählen, wie oft ich bereits Kernelemente der 3D-Engine umgebaut habe, weil beispielsweise plötzlich etwas anders war, als ich erwartet habe (Grafiktreiber, Direct3D, … OpenGL…) oder weil einfach auf irgendeiner Plattform (Stichwort: WinRT) irgendetwas grundsätzliches schlicht und ergreifend nicht geht.

Test-Diamant

Was sagt nun diese meine Pyramide oder besser „Diamant“ aus? Ich persönlich finde es bei meinen Anwendungen besser, Unit Tests nur bei ganz besonderen Funktionalitäten zu machen, welche auch wirklich kritisch sind. Ein aktuelles Beispiel sind hier wohl die Methoden, welche bei einem Animationssystem für die Basisberechnungen zuständig sind, und grundsätzlich zwischen Ereignisorientierter und Kontinuierlicher Methodik beliebig wechseln können (Infos dazu unter [4]). Die meisten meiner Testmethoden liegen aber auf der Ebene der Komponententests, insgesamt ist die Zahl der Tests aber weitaus geringer, als die „Tausenden von Tests“, welche häufig und auch im oben genannten Vortrag empfohlen werden. Zum Schluss gibt es noch die Gui-Schicht, wobei ich diese aber in Massen- und Einzeltests unterscheiden möchte. Und das ist für mich ein extrem wichtiger Punkt.. Masse! Es muss für mich sichergestellt sein, dass sämtliche UIs auch mit Massendaten zurechtkommen. Und spätestens hier fallen die wirklich feinen Mängel, beispielsweise bei der Thread-Synchronisierung auf.

Wie komme ich also zu diesem „Test-Diamant“? Diese Frage stelle ich mir selber auch häufig, klingen doch die Argumente für die Testpyramide oben sehr einleuchtend und machen auch so Sinn. Nur.. macht es für mich Sinn, zu wechseln? Ich denke nicht bzw. nicht im vollen Umfang. Der Grund, dass ein abweichendes Testvorgehen entsteht ist doch vielmehr, dass ein anderes Programm auch ganz andere Anforderungen hat. Der für mich wichtige Punkt Massentest beispielsweise kommt schlicht daher, dass ich den Großteil meiner Zeit an Multimedia-Programmen arbeite. Hierbei müssen stets mehrere Threads synchronisiert, Massendaten verarbeitet und immer eine flüssige und qualitativ hochwertige Darstellung gewährleistet werden – ohne umfassende Tests direkt an der Gui kann das nur schwierig sichergestellt werden. Der Tester sieht schließlich sofort, wenn es ruckelt (Performance), offensichtlich falsche Werte berechnet werden (Funktionalität, Thread-Synchronisierung) oder schlicht die UI blockiert oder ansonsten irgendetwas grundlos stehen bleibt.

Ähnliches denke ich auch über die Diskussionen, welche im Rahmen des Vortrags entstanden sind. Es kamen grundsätzlich verschiedene Ansichten von „Primär geht es doch um Test-Coverage“ oder „Ein einmal geschriebener Test darf nie wieder verändert werden, da er Teil der Spezifikation ist“… oder der Klassiker: „Hey, wie teste ich eigentlich die Datenbankanbindung?“. Alles stimmige Aussagen, nur treffen diese nicht bei jedem Fall zu. Nehmen wir etwas das Thema der Unveränderlichkeit eines Tests. Ich könnte mir vorstellen, dass diese Aussage so aus klassischen IT-Projekten kommen kann, welche X Monate oder Jahre dauern und am Termin X abgenommen werden. Klar, wenn ich hier sage, dass eine bestimmte Funktion im Testfall XY genau das Objekt Z mit Zustand VW zurückgeben muss, dann steht das fest und ist unveränderlich – alles andere wäre eine Änderung in der Spezifikation. Für mich war diese Aussage erst einmal unverständlich, da ich aus einer längerfristigen Entwicklung komme. Hier ist regelmäßiges Refactoring sehr wichtig, damit man nicht Gefahr läuft, von der Zeit überholt zu werden. Hierbei kann es sich auch um solche Refactorings handeln, dass eine komplette Library rausgeschmissen wird – so bereits passiert, da die Entwicklung davon vor Jahren eingestellt wurde. Aus dieser Sichtweise kommend ist es für mich ganz normal, dass automatisierte Tests regelmäßig angepasst werden.. schließlich müssen auch diese Schritt halten.

Nun wieder zur ursprünglichen Frage: Um was geht es nun beim Testen?
Letzten Endes geht es für mich darum, dass die Software stabil läuft. So banal, wie dieser Satz auch klingt… aber hier liegt für mich die höchste Priorität. Wie genau das erreicht wird, ist erstaunlicher Weiße je nach Anwendungsgebiet höchst unterschiedlich, auch wenn Ansätze wie obige Testpyramide helfen, anfangs eine Orientierung zu finden oder sein jeweils aktuelles Konzept zu überdenken, so entwickelt sich bei jedem etwas anderes daraus.

Links & Literatur
[1] Link zum Vortrag (IT-Speicher Regensburg)
[2] Eine Tour durch die Testpyramide
[3] Beispiel-Komponenten-Test bei SeeingSharp
[4] Wikipedia zu „Discrete Event Simulation“

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.