Überdeckungs-, Last- und Stresstest Stefanie Brose, Linh Phong Le Methoden und Werkzeuge zur Softwareproduktion Technische Universität Berlin WS 2004/2005 stefanie.brose@gmx.net, llphong@web.de Abstract Es gibt keine fehlerfreie Software. Überdeckungstest sind strukturorientierte Testtechniken, die Quellecode eines Programms möglichst viel abdecken. Last- und andere Systemtest berücksichtigen nicht funktionale Eigenschaften eines System. Keywords: Überdeckungstest, Lasttest, Stresstest, LCSAJ, Kontrollfluss, Clover, Optimizeit, LoadDriver, NetworkTester, Application Center Test 1 Einleitung Im folgenden werden verschiedene Überdeckungstestverfahren vorgestellt. Des weiteren zwei Tools für Überdeckungstest gezeigt. Weitere Themen sind Lasttest und Stresstest, die aber im Verhältnis zum Überdeckungstest nur kurz vorgestellt werden sollen. 2 Überdeckungstest Überdeckungstests sind dynamische kontrollflussorientierte Testverfahren. Das Ziel hierbei ist es, mit möglichst wenigen Testfällen, alle Teile des gegebenen Programmcodes auszuführen. Es ist natürlich wichtig, eine geeignete Menge von Testfällen zu finden, was die eigentliche Schwierigkeit bei Überdeckungstests darstellt. Bei den einzelnen Verfahren sollen unterschiedliche Kriterien erfüllt werden. So will man beim Anweisungsüberdeckungstest alle Anweisungen überdecken bzw. ausführen und beim Zweigüberdeckungstest bei allen Entscheidungen (z.b. if-abfrage) beide Wahrheitswerte. Weitere Überdeckungskriterien wollen wir nun vorstellen. 2.1 Bedingungsüberdeckungstest Hier werden die logischen Strukturen der einzelnen Entscheidungen geprüft. Dabei muss man unterscheiden zwischen condition und decision. Condition, das bezeichnet beim Überdeckungstest atomare Teilentscheidungen. Das sind Entscheidungen, die sich nicht aus anderen Entscheidungen zusammensetzen. Decision hingegen bezeichnet Gesamtentscheidungen. Eine interessante Frage, die man mit Bedingungsüberdeckungstests beantworten möchte, ist, inwiefern conditions und decision zusammenhängen. Mcdc, ein Verfahren zu dem wir später kommen, ist in der Lage, diese Frage zu beantworten. Doch vorab stellen wir andere Bedingungsüberdeckungstestverfahren vor, auf denen mcdc aufbaut. Hier sei kurz der Begriff subsumieren erklärt. Ein Verfahren A subsummiert ein Verfahren B, wenn A die 1
gleichen Kriterien wie B und noch zusätzliche erfüllt. Hat das zu testende Programm keine 100%ige Überdeckung für B, so gilt dies auch für A. 2.1.1 Einfacher Bedingungsüberdeckungstest (simple condition coverage) Hier werden alle atomaren Teilentscheidungen in der zu untersuchenden Gesamtentscheidung auf true und false getestet. Das muss aber nicht zur Folge haben, dass auch das Gesamtergebnis auf beide Wahrheitswerte getestet wird. Z.B. bei der Verknüpfung (A&&B) C erreichen die Testfälle mit 1. A=w, B=w, C=f und 2. A=f, B=f, C=w eine 100%ige einfache Bedingungsüberdeckung, aber das Endergebnis ist in beiden Fällen wahr. Es wird also nicht einmal eine vollständige Zweigüberdeckung, das Minimalkriterium kontrollflussorientierten Testens, erreicht. Der einfache Bedingungsüberdeckungstest ist also ein viel zu schwaches Testkriterium und nicht zu empfehlen. 2.1.2 Bedingungs-/Entscheidungsüberdeckungstest (condition/decision coverage) Hier sollen alle atomaren Teilentscheidungen und die Gesamtentscheidung auf true und false getestet werden. Dies subsumiert also den einfachen Bedingungsüberdeckungstest und den Zweigüberdeckungstest. Das Verfahren erklärt aber noch keine Zusammenhänge zwischen den atomaren Teilentscheidungen und der Gesamtentscheidung. Wir haben also mit dem Bedingungs-/Entscheidungsüberdeckungstest immer noch einen zu schwachen Test. 2.1.3 Minimaler Mehrfach-Bedingungsüberdeckungstest (simple multiple coverage) Hier werden alle Teilentscheidungen und die Gesamtentscheidung auf true und false getestet. Wir betrachten also auch Verknüpfungen von atomaren Teilentscheidungen, die die Gesamtentscheidung beinhaltet. Dies subsumiert die Bedingungs-/Entscheidungsüberdeckung. So kann man Teilentscheidungen herausfiltern, wie z.b. ( A A), die immer den gleichen Wahrheitswert (in diesem Falle ist das true) annehmen. Dieses Testverfahren ist also schon recht gut und durch seinen linearen Aufwand auch tragbar. 2.1.4 Modifizierter Bedingungs-/Entscheidungsüberdeckungstest (modified condition/decision coverage - mcdc): Hier werden wie beim minimalen Mehrfachbedingungsüberdeckuungstest alle Entscheidungen auf wahr und falsch getestet. Doch beim mcdc werden Testfälle gesucht, mit denen man die Abhängigkeit der Gesamtentscheidung von jeder einzelnen atomaren Teilentscheidung erkennen kann. Es muss also für jede atomare Teilentscheidung eine Paarung von zwei Testfällen gefunden werden, wo sich diese atomare Teilentscheidung als einzige in ihrem Wahrheitswert verändert und mit ihr auch der Wahrheitswert der Gesamtentscheidung. Findet man eine solche Paarung nicht, so kann man davon ausgehen, dass diese atomare Teilentscheidung keinen Einfluss auf das Gesamtergebnis der Entscheidung hat und daher überflüssig ist. Zumindest gilt dies dann für unsere Testfälle. Man muss natürlich noch zusätzlich betrachten, ob diese Menge von Testfällen repräsentativ genug für alle Testfälle ist. Bisher haben wir uns nur mit den Wahrheitswerten der atomaren Teilentscheidungen und der Gesamtentscheidung beschäftigt. Doch was ist mit den Entscheidungen dazwischen? Nun, wenn eine atomare Teilentscheidung nur in einer Verknüpfung innerhalb der Gesamtentscheidung auftritt und deren Wahrheitswert verändern soll, so muss sie doch erst den Wahrheitswert der Verknüpfung verändern. So werden also automatisch auch alle anderen Entscheidungen außer den atomaren und der gesamten mit auf wahr und falsch getestet und somit subsumiert mcdc den minimalen Mehrfachbedingungsüberdeckungstest. 2
Bei n atomaren Teil-entscheidungen braucht man mindestens n+1 Testfälle. Der Aufwand ist also linear und somit vertretbar. Man kann also sagen, dass es sich bei mcdc um ein sehr gutes Testverfahren handelt. 2.1.5 Mehrfach-Bedingungsüberdeckungstest (multiple coverage): Hier werden einfach alle Wahrheitswertekombinationen betrachtet, die es gibt. Somit subsumiert der Mehrfach-Bedingungsüberdeckungstest alle anderen Bedingungsüberdeckungstests, was natürlich sehr gut ist. Aber dieses Verfahren ist viel zu aufwendig, da es bei n atomaren Teilentscheidungen 2^n Wahrheitswertekombinationen gibt und diese sind nicht immer alle realisierbar. Daher lässt sich auch kein richtiges Testmaß wie z.b. beim Zweigüberdeckungstest finden. Der Mehrfach- Bedingungsüberdeckungstest ist also nicht zu empfehlen. 2.2 Boundary-Interior Pfadüberdeckungstest Programme haben wegen Schleifen oft äußerst viele Programmpfade. Deshalb ist es kaum möglich, einen vollständigen Pfadüberdeckungstest durchzuführen, der alle Pfade überdeckt. Lösung zu diesem Problem ist, Pfade werden in Äquivalenzklassen unterteilt und nur Vertreter aus diesen Klassen werden ausgeführt. Bei Boundary-Interior Pfadüberdeckungstest werden Pfade mit höchsten zwei Schleifendurchläufen betrachtet. Ein Boundary-Interior Pfadüberdeckungstest besteht aus drei Tests: Test Außerhalb der Schleife: keine Schleife wird betreten Boundary-Test: jede Schleife wird einmal betreten aber nicht wiederholt Interior-Test: jede Schleife wird zweimal ausgeführt Trotz der Beschränkung von Schleifendurchläufen wächst der Testaufwand sehr schnell, wenn das Programm mehrere verschachtelte Kontrollkonstrukten hat. Ein anderes Problem ist, dass ein Pfad nur ab i-ten Ablauf, i > 2, ausführbar ist. 2.3 Modifizierter boundary-interiror Test Liggesmeyer hat eine Testtechnik vorgeschlagen, den er modifizierte Boundary-Interior Pfadüberdeckungstest genannt hat. Funktionsweise dieser Methode: Jede Schleife wird einzeln betrachtet, dabei wird die umgebende Kontrollstruktur ignoriert. Ebenfalls werden Pfade vernachlässigt, die durch eingeschachtelte Schleifen entstehen. Außerdem lassen sich mehrere Tests durch einen Testfall durchführen. So wird Testaufwand reduziert. 2.4 Strukturierter Pfadüberdeckungstest Strukturierter Pfadüberdeckungstest ist der verallgemeinerte Fall von Boundary-Interior Pfadüberdeckungstest. Hier werden aber mehr als zwei Schleifendurchläufen berücksichtigt. 3
2.5 LCSAJ-Test LCSAJ steht für Linear Code Sequence And Jump. Diese für Programmiersprachen mit Sprüngen gedachte Testtechnik liegt zwischen Zweigüberdeckungs- und Pfadüberdeckungstest. Da Sprachen mit Sprüngen nicht mehr populär sind, verliert auch das Testverfahren Bedeutung. Eine lineare Codesequenz wird als eine Folge von sequentiellen Anweisungen definiert, die mit einem Sprung beendet wird. Eine LCSAJ besteht also aus der ersten und der letzten Anweisung der LCSAJ, sowie dem Sprungziel. Um den Test auch für Sprachen ohne Sprung anwendbar zu machen, wird die Sprungdefinition erweitert. Sprung ist ein Kontrolltransfer von einer Zeile zu einer anderen Zeile unter der Voraussetzung, dass zwischen den zwei Zeilen ausführbarer Code existiert Ziel dieser Testtechnik ist die Überdeckung aller möglichen lineare Codesequenzen eines Programms. In diesem Fall, erreicht auch der Zweigüberdeckungstest 100%-ige Überdeckung. 2.6 Werkzeuge für Überdeckungstest Es gibt für fast alle gängigen Programmiersprachen Überdeckungstestwerkzeuge. Beispiele sind: für Ada: Ada95 Test Coverage Tools (http://www.ddci.com/news_ada95_testtools.shtml) für Delphi: Discover for Delphi (http://www.cyamon.com/discover1.htm),, Time1 (http://www.cyamon.com/time1.htm) für Java: jcoverage (http://jcoverage.com/), Koalog Code Coverage (http://www.koalog.com/php/kover.php), Java Test Coverage Tool (http://www.semdesigns.com/products/testcoverage/javatestcoverage.html), Clover (http://www.cenqua.com/), OptimizeIt (www.borland.com) Von diesen Werkzeugen sind Clover und Optimizeit am interessantsten. 2.6.1 Clover Clover kommt als Plugin für Eclipse, IDEA, JBuilder und JDeveloper. Clover arbeitet instrumental. Zähler werden zunächst in Quellecode eingefügt, der Code wird dann kompiliert und ausgeführt. Es werden am Ende gezeigt, welche Methoden und Anweisungen überdeckt wurden, wie viele Male eine Bedingung wahr oder falsch war. Da der modifizierte Code in einem von Clover extra erstellten Verzeichnis liegt, bleibt der originale Code unberührt. Ergebnis ist außerdem als html-, pdf- oder xml-bericht zu speichern. 2.6.2 OptimizeIt Borland Optimizeit ist eine Suite, die Profiler, Thread Debugger und Code Coverage enthält. Code Coverage (Anweisungsüberdeckung) lässt sich in JBuilder integrieren und kann auch allein stehend arbeiten. Im Gegenteil zu Clover kann Code Coverage auch ohne Quellcode Anweisungsüberdeckungstest durchführen. Der Code muss allerdings mit Debug- Information kompiliert werden. Ergebnis lässt sich als ascii oder html exportieren. 4
2.7 Bewertung von Überdeckungstests Überdeckungstests haben einen sehr hohen Stellenwert. Man sollte zumindest eine Zweigüberdeckungstest durchführen. Doch wenn man ein wirklich gutes Testverfahren haben möchte, so sollte man mcdc und den modifizierten Boundary-interior Test wählen. 3 Lasttest und Stresstest Lasstest ist ein Teil von mehreren Systemtest (Sicherheitstest, Performanztest, Test auf Benutzungsfreundlichkeit,...). Mit Lasstest wird das Verhältnis eines Systems in Abhängigkeit steigender Systemlast (Anzahl Anwender, Anzahl Transaktionen, ) beobachtet. Ein Stresstest ist nicht anderes als ein Lasstest, indem man die Kapazität des System absichtlich überschreitet. Ein System kann z.b. maximal 100 Benutzer gleichzeitig bedienen. Es wird aber versucht, von 120 Benutzern zeitgleich benutzt zu werden. Ziel ist zu testen, ob das System mit umfangreichen Datenvolumen richtig funktioniert, ob es in einer akzeptablen Zeit antworten kann und in langer Zeit zuverlässig läuft. Es gibt mehrere Testarten: Massentest: es wird getestet ob das System eine große Datenmenge richtig bearbeiten kann. Laut Pflichtenheft kann z.b. eine Banksoftware 1 Million Konten von 10 verschiedenen Kontoarten verwalten. Zum Test muss dann für jede Kontoart 1 Mio. Konten eingegeben werden. Zeittest: die Antwortzeit (von der Benutzeroberfläche oder von einem Server im lokalen Netwerk) wird gemessen. Mehrbenutzertest: es wird oft mit einem Werkzeug mehrere parallel arbeitende Benutzer simuliert. Beispiel: um einen Webserver zu testen, wird simuliert, als ob tausende Benutzer mit verschiedenen Webbrowsern unter verschiedenen Plattformen gleichzeitig auf den Server zugreifen. Die meisten Lasttests in Praxis werden mit Werkzeugen durchgeführt. Werkzeuge für Lasttest sind oft 2 in 1, Lasstest und Performanztest, und werden für Webapplikationen entwickelt. Beispiele sind: LoadDriver (http://www.inforsolution.com/): führt gleichzeitig tausende echte Instanzen MSIE Webbrowser aus. NetworkTester (http://www.agilent.com/comms/networktester/): simuliert Millionen Benutzer und Services, testet Netzverkehre mit Protokollen wie DNS, HTTP, FTP, NNTP, POP3, SMTP, NFS, CIFS, IM, Microsoft Application Center Test (http://msdn.microsoft.com/library/default.asp?url=/library/enus/act/htm/actml_main.asp): ein Tool für MS Visual Studio.NET Referenzen P. Liggesmeyer Software Qualität - Testen, analysieren und verifizieren von Software A. Spillner, T. Linz Basiswissen Softwaretest H. Trauboth Software-Qualitätssicherung Software QA and Testing Resource Center: http://www.softwareqatest.com/ 5