Bundesamt für Sicherheit in der Informationstechnik

M 2.568 Testverfahren für Software

Verantwortlich für Initiierung: Behörden-/Unternehmensleitung, Leiter IT

Verantwortlich für Umsetzung: Tester

Um die Qualität von Software zu sichern, existieren statische Verfahren, bei denen das Programm nicht ausgeführt wird, und dynamische Verfahren während der Laufzeit.

Statische Verfahren

Bei statischen Verfahren wird der Programmcode verifiziert. Bedeutende statische Verfahren sind Code Reviews und die automatische statische Code Analyse.

Code Reviews

Bei der Entwicklung von Systemen sollten Code Reviews stattfinden, da es hardwareabhängige Fehler gibt, die nur so mit vertretbarem Aufwand gefunden werden können. Der Aufwand dafür sollte sich am Schutzbedarf und am Kosten-Nutzen-Verhältnis orientieren. Eine einfache, wenig formale Variante ist ein sogenannter Walkthrough, in dem der Autor schrittweise sein Gewerk präsentiert und die Teilnehmer Rückmeldungen geben. Bei höheren Sicherheitsanforderungen sollte eine formale Code-Inspektion durchgeführt werden. Beide Arten können auch als Peer Reviews durchgeführt werden. Dabei ist neben dem Autor nur ein weiterer, hierarchisch gleichgestellter Mitarbeiter beteiligt. Peer Reviews senken die Kosten und bringen oft nur einen vertretbaren Sicherheitsverlust mit sich. Reviews sollten sich an einer Checkliste orientieren, die z. B. folgende Fragen enthalten kann:

  • Können Feld-Indizes überlaufen?
  • Sind alle Variablen im richtigen Kontext definiert?
  • Ist die Bit-Breite der Variablen ausreichend?
  • Werden arithmetische Überläufe erkannt und behandelt?
  • Werden bekannte fehlerträchtige Konstrukte vermieden?

Automatische statische Code Analyse

Zur automatischen statischen Code Analyse sind Werkzeuge mit einer großen Preisspanne am Markt. Es gibt sowohl kostengünstige als auch hochpreisige Werkzeuge. Kostengünstige Werkzeuge können bereits eine Vielzahl an Analysemethoden aufweisen und z. B. den Kontroll- und den Datenfluss analysieren, nach nicht initialisierten Variablen suchen und Zahlenwerte verfolgen. Neben den zusätzlichen Analysemöglichkeiten liegen die Vorteile der hochpreisigen Systeme darin, dass sie besser bedienbar sind und deutlich weniger false positives erzeugen. Einen Hinweis auf die Qualität von Code können auch Code Metriken geben, wie z. B. die Verschachtelungstiefe, die Anzahl dynamisch erzeugter Objekte oder die Kommentardichte.

Dynamische Verfahren

Beim dynamischen Verfahren wird das fertige Programm oder Teile davon validiert. Dabei wird die zu testende Software mit systematisch festgelegten Testdaten ausgeführt. Testdaten bestehen aus Vor- und Nachbedingungen und bilden mit der zu testenden Funktion einen Testfall. Beim Testen sollen vor allem Programmfehler erkannt werden, die in Abhängigkeit von dynamischen Laufzeitparametern auftreten, wie z. B. Sensordaten oder Nutzer-Interaktionen. Allgemein sind die Phasen beim Testen wie folgt gegliedert:

  • Herstellung der Vorbedingungen des Testfalls
  • Ausführung des Programms oder der Teilfunktion des Testfalls
  • Vergleich des erwarteten Werts mit dem tatsächlich gelieferten Wert und Überprüfung der Nachbedingungen
  • Abbau des Testfalls

Dabei kann bereits während der Entwicklung des Software-Designs parallel mit dem Test-Design begonnen werden. So kann die Testphase verkürzt werden und es können Testfälle identifiziert werden, für die spezielle Test-Hardware benötigt wird. Dynamische Tests können beginnen, wenn die ersten Module der Software fertig gestellt sind. Anstatt Testfälle erst zum Schluss festzulegen, können Testfälle auch vor der Implementierung angelegt werden und steuern auf diese Weise die Entwicklung maßgeblich. Dieses Vorgehen wird testgetriebene Entwicklung (englisch: Test-Driven-Development, TDD) genannt.

Tests können auf unterschiedlichen Arten hergeleitet werden. Grundlegende Kategorien sind

  • spezifikationsorientierte Verfahren, sogenannte Black-Box-Tests, und
  • strukturorientierte Verfahren, sogenannte White-Box-Tests.

Tests haben verschiedene Ebenen der Granularität und Ausführungsreihenfolge. Die übliche Reihenfolge, in der Software getestet wird, ist:

  • Komponententest
  • Integrationstest
  • Systemtest

Dabei hat der Komponententest die niedrigste Granularität und der Systemtest die höchste. Es sollten auch alle Komponententests abgeschlossen sein, auf die ein Integrationstest aufbaut. Das Gleiche gilt für Systemtests. Ein weiterer wichtiger Aspekt ist, wie Tests ausgeführt werden.

Black-Box-Test

Bei einem Black-Box-Test wird der Testgegenstand gegen seinen im Design spezifizierten Zweck getestet. Neben der erwarteten Funktionalität ist das Verhalten bei ungewöhnlichen Eingaben zu testen. Da fast nie alle möglichen Eingaben und Ausgaben getestet werden können, sind Äquivalenzklassen zu bilden. Diese sollten so eingeteilt werden, dass der Tester davon ausgeht, dass sich die jeweiligen Eingaben aus einer Äquivalenzklasse gleich verhalten. Tests sind verstärkt mit den Grenzwerten einer Äquivalenzklasse durchzuführen, also z. B. den betragsgrößten und -kleinsten negativen und positiven Werten. Auch der Wert Null und Werte in seiner Umgebung sollten getestet werden.

White-Box-Test

Bei White-Box-Tests werden die Testfälle aufgrund des Softwarequellcodes bestimmt. Sie können grob unterteilt werden in komplexe, in der Praxis nicht weit verbreitete datenflussorientierte Methoden und kontrollflussorientierte Methoden. Bei letzteren hängt die Aussagekraft von der Testabdeckung ab. Diese ist definiert als der prozentuale Anteil von Einheiten wie z. B. Anweisungen und Zweige einer Software, der durch Tests bereits ausgeführt wurde. Unterschiedliche Grade der Testabdeckung werden mit Überdeckungstests erreicht, die auf Grund der geringeren Größe der Testobjekte besonders für Komponententests geeignet sind. Die gebräuchlichsten Metriken dafür sind, sortiert nach zunehmender Strenge:

  • Anweisungsüberdeckung (statement coverage): Die einfachste Metrik zur Testabdeckung prüft welcher Anteil der Programm-Statements ausgeführt wurde. 100% Anweisungsüberdeckung gilt als relativ schwacher Nachweis und genügt höchstens bei Systemen mit geringem Schutzbedarf.
  • Zweigüberdeckung (branch coverage): Es wird geprüft, ob bei jeder Verzweigung jede Option mindestens einmal durchlaufen wurde.
  • Verzweigungs- und Bedingungsabdeckung (decision and condition coverage): Zusätzlich zur Zweigüberdeckung wird eine Änderung jeder Teilbedingung eines Booleschen Ausdrucks gefordert.
  • Modifizierter Bedingungs-/Entscheidungsüberdeckungstest (modified decision and condition coverage): Jede der Teilbedingungen, die auf eine Verzweigung Einfluss haben kann, muss zeigen, dass sie unabhängig von den anderen den Programmfluss bestimmen kann.

Komponententest

Komponententests beziehen sich auf die kleinsten sinnvoll isoliert testbaren Einheiten. Sie können als Black-Box- und/oder White-Box-Tests durchgeführt werden. Komponententests sollten auf dem Zielsystem ablaufen, da es nur dadurch möglich ist, Compilerfehler zu finden und mögliche Interpretationsfreiheiten zu erkennen, die zu unterschiedlichen Ergebnissen auf einem Host- und einem Zielsystem führen könnten. So ist z. B. bei C-Compilern das Ergebnis eines Rechts-Shifts eines negativen Integer-Wertes nicht exakt definiert oder Datenbreite und Endianess können an Host- und Zielsystem unterschiedlich sein.

Integrationstests

Mittels Integrationstests wird geprüft, ob Softwarekomponenten miteinander und mit Hardwarekomponenten korrekt zusammenwirken. Dabei werden die Testfälle als Black-Box-Tests ausgeführt. Typische Methoden für Software/Software-Integrationstests sind Bottom-Up-Komponententests, strukturierte Integrationstests und die Messung der Testabdeckung der Aufrufe von Unterprogrammen. Jede Methode hat Stärken und Schwächen. Bottom-Up-Komponententests können für kleine Projekte sinnvoll sein, wenn keine zyklischen Abhängigkeiten der Komponenten vorliegen. Strukturierte Integrationstests und die Messung der Testabdeckung der Aufrufe von Unterprogrammen sind problematisch, wenn globale Variablen verwendet werden. Ein Nachteil der letztgenannten Strategie ist auch, dass Fehler bei der Integration erst relativ spät erkannt werden.

Ziel des Hardware/Software-Integrationstests ist es, das Zusammenwirken von Hard- und Software zu überprüfen. Ist die Zielumgebung von Anfang an verfügbar, können Bottom-Up-Komponententests stets darauf laufen. Beim Regressionsverfahren werden die Zugriffe auf die Hardware durch eine Abstraktionsschicht gekapselt. Hat das System einen hohen Schutzbedarf, sind bei den Analysen auch alle denkbaren Fehlerzustände der Hardware zu betrachten und die Ergebnisse genau zu dokumentieren, idealerweise gibt es zu jedem funktionalen Merkmal und jedem Fehlverhalten einer Schnittstelle einen nachgewiesenen Test.

Wegen der möglicherweise beschränkten Ressourcen ist es bei einigen Systemen auch wichtig Ressourcentests durchzuführen. In diesen ist zu prüfen, ob die CPU und der vorhandene Speicher für die vorgesehene Software ausreichend leistungsfähig bzw. dimensioniert sind.

Systemtests

Mittels Black-Box-Tests wird überprüft, ob das System insgesamt die spezifizierten Anforderungen erfüllt. Begleitend sollte mittels Traceability-Tabellen verfolgt werden, welche Anforderung in welchem Test geprüft wird. Die Testdaten werden durch Äquivalenzklassenbildung über gültige und ungültige Eingangsdaten gebildet. Pro Testfall darf nur ein einziger Wert aus einer Äquivalenzklasse mit ungültigen Werten genommen werden.

Ausführungsarten von Tests

Tests können manuell, halbautomatisch oder automatisch ablaufen. Eine hohe Testautomatisierung bietet den Vorteil, sich wiederholende Tests schnell und unkompliziert durchführen zu können. Sie ist z. B. besonders für Regressionstests geeignet, also Tests die nach einer Fehlerbehebung durchgeführt werden um sicher zu gehen, dass dadurch nicht Fehler an anderer Stelle erzeugt wurden. Sie macht es auch möglich, manuell nur schwer zu realisierende Tests wie z. B. Lasttests wirtschaftlich durchzuführen. Beim Test sind gegebenenfalls notwendige manuelle Eingriffe zu berücksichtigen, beispielsweise beim Testen von eingebetteten Systemen.

Prüffragen:

  • Werden Code Reviews und eine automatische statische Codeanalyse durchgeführt?

  • Werden bei den Komponententests sinnvolle Äquivalenzklassen gebildet und alle kritischen Grenzwerte getestet?

  • Ist die zur Testabdeckung gewählte Metrik dem Schutzbedarf angemessen und werden Komponententests auf dem Zielsystem durchgeführt?

  • Werden dem Schutzbedarf angemessene Integrationstests und Systemtests durchgeführt?

  • Wird getestet, ob die CPU und der vorhandene Speicher für die vorgesehene Software ausreichend leistungsfähig bzw. dimensioniert sind?

Stand: 15. EL Stand 2016

Hinweis zur Verwendung von Cookies

Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen hierzu erhalten Sie in unserer Datenschutzerklärung.

OK