Testautomatisierung

Applikationen auf Herz und Nieren geprüft: Lasttests in DevOps

In DevOps-Organisationen wird ein hoher Automatisierungsgrad angestrebt. Alle notwendigen Operationen sollen möglichst automatisiert ablaufen, darunter auch der Test. DevOps verlangt hier kleine Testszenarien anstatt große komplexe Tests, um deine hervorragende Userexperience zu garantieren. Mögliche Herangehensweisen dazu habe ich in diesem Blogbeitrag zusammengefasst.

DevOps as a binary code with blurred background 3D illustration

Im Test unterscheiden wir generell zwischen funktionalen und nicht-funktionalen Tests. Der Last- und Performance-Test (LPT) ist dem nicht-funktionalen Test zugeordnet. Wird ein LPT im Continuous Testing Prozess eingesetzt, wird dieser üblicherweise nach dem funktionalen Test eingetaktet, um sicherzugehen, dass alle funktionalen Voraussetzungen erfüllt sind, bevor das Performance-Verhalten auf Herz und Nieren geprüft wird.

In diesem LPT Schritt werden die Qualitätsmerkmale (ISO 25000 bzw. ISO 9126), Effizienz (Zeit Verhalten und Ressourcen Verhalten) sowie Robustheit betrachtet. Die Performanz einer Anwendung gewinnt in Bezug auf die User-Experience stark an Bedeutung.

Ein weiterer wichtiger Aspekt in der Integration des LPT in Continuous Delivery bzw. Continuous Deployment, sind die speziellen Anforderungen an die Testumgebungen (Lastgeneratoren, Anzahl der Testdaten, produktionsnahe Testumgebung, etc.). Es ist wichtig, dass wir ein schnelles Feedback der Testergebnisse bekommen, unter anderem damit die Entwickler diese frühzeitig beseitigen können.

Innerhalb von DevOps ist das meiste automatisiert; vom Build über Test bis hin zum Deployment. Die Ergänzung dieser automatisierten Kette um LPT stellt innerhalb von DevOps keine große technische Herausforderung mehr dar. Lösungen über Clouddienste wie LPT Services oder UI-Less LPT Tools unterstützen hier.

 

Kleine Testszenarien statt komplexe Tests

Ein Last- und Performance Test skaliert per Definition. In DevOps ist aber die Perspektive tendenziell etwas anders als bei punktuellen Performancetests: Große und langwierige LPT sind hier kontraproduktiv. Sie dauern lange und sind aufwendig in der Analyse. Für DevOps werden kleine Testszenarien benötigt, die sich außerdem gut parallelisieren lassen.

Diese Testszenarien schließen nun nicht mehr das gesamte Testobjekt samt den umliegenden Systemen ein. Vielmehr wendet sich der LPT-Tester den Features zu, die für eine hervorragende Userexperience entscheidend sind. Zu Beginn habe ich erwähnt, dass in einem LPT die Robustheit mit betrachtet werden soll. Das Qualitätsmerkmal „Robustheit“ ist laut ISO Norm die „Robustheit des Produktes im Betrieb“. Umgangssprachlich verwenden wir dafür oft das Synonym „Stabilität“, was ich auch hier tun will. Die Stabilität umfasst dabei nicht nur die Antwort auf die Frage „Crasht das System?“, sondern die Suche nach Instabilitäten in den Backendsystemen.

Tauchen in einem Performancetest Fehler aus dem Nichts auf, deutet dies naturgemäß auf eine Instabilität in dem System hin, die untersucht werden sollte. Diese Instabilitäten wird der Endbenutzer als ärgerlich empfinden, da „schon wieder etwas nicht funktioniert“. Solche Fehler treten auch in der funktionalen Testautomatisierung hin und wieder auf. Sie dürfen aber keinesfalls als harmloser „Schluckauf“ abgetan werden. Solchen Fehlern ist unbedingt nachzugehen, dazu können die Performance Tests verwendet werden.

In den meisten Projekten wird ein LPT auf einer eigenen, dedizierten Umgebung durchgeführt. Diese Umgebung sollte der Produktivumgebung so nah wie möglich kommen. Die Testszenarien werden auf Basis von Geschäftsfällen aufgebaut – sie sind meistens komplex, aufwendig und erfordern lange Vor- und Nachbearbeitungszeiten.

Die Frage, die wir uns nun stellen müssen, ist: Wie können wir komplexe LPT in DevOps herunterbrechen? Genauer: Ist es legitim, viele kleine Testszenarien durchzuführen, anstatt einen langen und komplexen Test? Und Welche Tests sind praxisnah und welche nicht?

 

LPTs und Testszenarien in der Praxis

Je nach Anzahl der simulierten Benutzer dauern LPT eine gewisse Zeit, 20 Minuten bis mehrere Stunden oder sogar Tage. Solche Zeitspannen sind in einer DevOps Umgebung vollkommen praxisfern. Es ist daher wichtig, regelmäßige Checks einzuplanen, welche die Applikation im Bereich der Performance-Anforderungen überprüft. Ein Stresstest bzw. ein 24-Stunden-Lasttest sind solche Kandidaten.

Ein Stresstest überprüft das Lastverhalten der Anwendung in Grenzbereichen. Man versucht herauszufinden, welche maximale Last die Applikation aushält, in dem man bewusst über die technischen Grenzen der Anwendung hinausgeht. In einer DevOps Umgebung, wo nach jedem Deployment der Server einmal absichtlich zum Absturz gebracht werden würde, wäre das nicht besonders praktikabel.

Auch ein 24 Stunden Test ist der Prämisse, schnelle und unkomplizierte Deployments zu haben, entgegengesetzt. Ein Deployment, bei dem nach 24 Stunden der Server gekillt wird, ist jedem Betriebler ein sehr fremder Gedanke. Solche Lasttests sind daher eigens einzuplanen. Diese Tests werden in regelmäßigen Abständen durchgeführt und dienen dem Finden von weiteren Optimierungspunkten. Schwachstellen können identifiziert und die Applikation optimiert werden. Diese (nennen wir sie „große LPTests“) decken das gesamte System ab.

Zurück zu den kleinen Lasttests, die in einer DevOps Umgebung stattfinden. Ich designe meine LPT immer nach Geschäftsfällen. Solche Testszenarien können in kleinere, weniger komplexe, Teile heruntergebrochen werden. Dazu überlegt man sich, wie der Geschäftsprozess geschnitten werden könnte. Aus diesen Teilen formt man nun unabhängige, leichtgewichtige Lasttestszenarien. Für das Herunterbrechen der Geschäftsprozesse arbeite ich immer mit den manuellen Testern oder den Testautomatisierern zusammen. Sie haben die nötige Erfahrung und den Überblick, welche Tests unabhängig sind und welche Vorbedingungen diese brauchen.

Jedes Testszenario hat Vorbedingungen. Diese müssen für einen erfolgreichen Durchlauf gegeben sein (Bsp: Username und Login), das bleibt uns nicht erspart. Das bedeutet aber auch, dass die Vorbedingungen redundant sind, und in jedem Testszenario vorkommen. Dieses Thema ist oft eng mit Testdaten verknüpft.

Im LPT werden in der Regel enorme Mengen an Testdaten erzeugt und verbraucht. Das Testdaten-Thema sollte daher nicht unterschätzt werden. Jedes DevOps Testszenario erhält eigene Testdaten-Pools. Damit ist gewährleistet, dass die Tests parallel durchgeführt werden können, weil sie dadurch in ihren Daten unabhängig gestaltet sind.

In einem unserer Projekte haben wir dieses Problem recht einfach gelöst: Durch einen Snapshot des Datenbankbestandes. Vor jedem Lauf wurde die Datenbank auf diesen Stand zurückgesetzt, und daher die Datenbasis bereinigt und verbrauchte Testdaten wiederhergestellt.

 

Wir gehen so vor, dass wir für diese kleine Einheiten LPT erstellen, d.h. Lastprofile anlegen und die Umgebungen sowie die Testdaten so vorbereiten, dass diese kleinen Einheiten parallel ablaufen können. Ein Lastprofil beinhaltet die Anzahl der verwendeten User, die auf das System zugreifen; die Anzahl der Wiederholungen der Testszenarien, etc.

Diese Testläufe setzen wir so an, dass sie time-boxed sind, z.B. auf Beispiel 10min. Diese Dauer stört den CI bzw. CD nicht allzu sehr und liefert uns wichtige Informationen:

  1. wie unsere Applikation performed
  2. ob Performance Optimierungen greifen
  3. eine Aussage über die Robustheit der Applikation

Während der Projektlaufzeit bekommen so wichtige Trendkurven, wie unsere Applikation performed und können die verschiedene Builds miteinander vergleichen. Wir bekommen aber noch eine weitere sehr wichtige Rückmeldung: Die Robustheit der Applikation. Also das, was der Kunde positiv wahrnehmen wird!

Für das Last- und Stressverhalten müssen in regelmäßigen Abständen eigene Tests durchgeführt werden, die „großen Lasttests“. Dabei verwende ich eigene Testszenarien. Diese umfassen dann mehrere Geschäftsfälle und können Applikation durchgehend testen. Der Aufwand für die Entwicklung dieser Testszenarien ist im Allgemeinen nicht besonders hoch, da ich die „kleinen Einheiten“ wiederverwende und zu größeren Szenarien zusammensetze.

 

Der Nutzen von Last- und Performancetests im DevOps Zyklus

Der hohe Automatisierungsgrad in DevOps ermöglicht uns, schnell Information über das System zu erhalten. Anhand der Ergebnisse des Builds, der Testautomatisierung und dem LPT können, im Fehlerfall, schnell geeignete Maßnahmen gesetzt werden.

Der LPT erfordert besondere Vorbereitungen, sowohl bei Testdaten und den Umgebungen, aber auch beim Design der Testszenarien. Diese müssen leichtgewichtig, unabhängig und parallelisierbar sein.

Die Testergebnisse ergeben Aufschluss über die Stabilität und Performance der Applikation. Die wiederholte Ausführung ermöglicht das Tracking, wie die Optimierungen am System greifen. In regelmäßigen Abständen sollten große Stresstests und Lastests eingeplant werden, um das gesamte System unter Last setzen.

Die Stabilität und Performance einer Anwendung ist essentiell, da diese Qualitätsmerkmale direkt die Userexperience beeinflusst. Und wie wir alle wissen aus unser eigenen Erfahrung: eine stabile und performante Applikation freut den Benutzer!

Passende Artikel

Kommentare gesperrt.