In Abschnitt 9 von Teil 6 der ISO 26262 geht es um den Software-Unit-Test. Hierdurch soll gezeigt werden, dass die Software-Units ihre Designspezifikation erfüllen und keine unerwünschte Funktionalität beinhalten (Abschnitt 9.1). Eine Software-Unit definiert die Norm als eine nicht mehr weiter unterteilbare (atomare) Komponente der Software-Architektur, die jedoch für sich alleine genommen testbar ist (Teil 1, Abschnitt 1.125).

Was bedeutet diese Definition nun konkret? Nach wie vor ist der überwiegende Teil der sicherheitskritischen Software in Automobilen in C geschrieben. Nimmt man deswegen an, dass die zu testende Software in C geschrieben ist, kann man eine Software-Unit mit einer Funktion im Sinne von C gleichsetzen. Um zu verifizieren, dass eine Software-Unit Ihre Design-Spezifikation erfüllt, sind Tests eine der Methoden, die ISO 26262 (Teil 8, Abschnitt 9.4.1.1) nennt. Natürlich müssen die Testfälle in erster Linie aus der Spezifikation der Software-Unit abgeleitet werden, denn diese beschreibt unter anderem das funktionale Verhalten (Teil 6, Abschnitt 8.4.3). Welche ergänzenden Methoden hier noch in Frage kommen, wird weiter unten behandelt. Denn zunächst geht es um den Nachweis, dass keine unerwünschte Funktionalität durch die Software-Unit ausgeführt wird. Unerwünschte Funktionalität könnte beispielsweise die unerwünschte Möglichkeit zur späteren Kalibrierung (Stichwort „Tuning“) sein oder die Reaktion auf geheime Eingaben, die zu Testzwecken implementiert wurden oder die Ablage/Ausgaben von Daten zur späteren Auswertung, ebenfalls zu Testzwecken.

Auf einen Blick

ISO-26262-konformes Testen

In ihrem Teil 6 fordert die ISO-Norm 26262 auch Unit- und Integrationstests der Software. Ohne Werkzeugunterstützung ist diesen Forderungen praktisch kaum nachzukommen, denn neben dem reinen Test sind auch Nachweise über die erreichte Code-Überdeckung zu führen. Je nach Sicherheits-Level (ASIL) sind andere Überdeckungsmaße relevant. Außerdem bestehen besondere Anforderungen an die Software-Integrationstests.

Wenn man keine Vermutung über die unerwünschte Funktionalität hat, kann man ihre Abwesenheit streng genommen durch Testen nicht nachweisen, denn man müsste alle möglichen Eingaben ausprobieren und sicherstellen, dass keine zu einem unerwünschten Ergebnis führt. Dieses erschöpfende Testen ist wegen des Effekts der kombinatorischen Explosion in der Praxis nicht möglich.

Wie weist man die Abwesenheit von unerwünschter Funktionalität nach? Ein Ansatz kann die Messung der Codeüberdeckung sein. Auf dieses Thema geht dieser Beitrag später noch ein. Ist eine unerwünschte Funktionalität in einer Software-Unit implementiert und wurde die zugehörige Software während der Tests (die basierend auf den Anforderungen die gewünschte Funktionalität prüfen) nicht durchlaufen, wird die Codeüberdeckung nicht 100 % sein. Bei der Ursachenforschung hierfür wird die unerwünschte Funktionalität aufgedeckt werden. Dieser Ansatz sorgt natürlich nicht für 100-%ige Abwesenheit von unerwünschter Funktionalität, denn es ist durchaus vorstellbar, dass 100 % Codeüberdeckung eines bestimmten Maßes erreicht wird und trotzdem unerwünschte Funktionalität vorhanden ist.

Bild 1: Methoden zur Herleitung von Testfällen für den Software-Unit-Test. Ein einfaches Pluszeichen bedeutet „recommended“ (empfohlen), ein doppeltes Pluszeichen „highly recommended“ (in hohem Maße empfohlen).

Bild 1: Methoden zur Herleitung von Testfällen für den Software-Unit-Test. Ein einfaches Pluszeichen bedeutet „recommended“ (empfohlen), ein doppeltes Pluszeichen „highly recommended“ (in hohem Maße empfohlen).Hitex

Testfallspezifikation

In Tabelle 10 von Teil 6 der ISO 26262 wird an erster Stelle „anforderungsbasierter Test“ als eine der Methoden für die den Software-Unit-Test genannt. Diese Methode ist für alle Automotive Safety Integrity Level (ASIL) „highly recommended“. Bei dieser Methode dienen die Anforderungen an die Software-Unit, die man aus der Designspezifikation der Software-Unit erhält, als Ausgangspunkt. Damit ist mit „Analyse der Anforderungen“ auch schon die erste der Methoden genannt, die in Tabelle 11 von Teil 6 zur Herleitung von Testfällen für den Software-Unit-Test aufgeführt sind (Bild 1). Weitere genannte Methoden sind „Erzeugung und Analyse von Äquivalenzklassen“, „Grenzwertanalyse“ und „Fehler raten“. In Bild 1 bedeutet ein einfaches Pluszeichen „recommended“ und ein doppelte Pluszeichen „highly recommended“.

Es liegt auf der Hand, dass es zu einer Anforderung wie „die Eingabe von X soll das Ergebnis Y erzeugen“ einen Testfall geben muss, und es liegt auch auf der Hand, wie dieser anforderungsbasierte Testfall aussehen kann. Aber was ist die Bedeutung anderen genannten Methoden?

Äquivalenzklassen

Äquivalenzklassen (equivalence classes) kommen ins Spiel, wenn testrelevante Aspekte sehr viele Werte annehmen können. Testrelevante Aspekte sind Parameter des Testobjekts, die man zur Erstellung der Tests variieren möchte; dies sind üblicherweise die Eingaben des Testobjekts, beispielsweise Parameterwerte wie Lenkwinkel oder Geschwindigkeit. Insbesondere wenn es darum geht, mehrere Testaspekte zu kombinieren, kann man in der Praxis nicht alle Werte eines Aspekts mit allen anderen Werten eines Aspekts kombinieren, weil man dabei zu viele Testfälle erhalten würde (kombinatorische Explosion).

Um zu einer handhabbaren Menge von Werten für einen Aspekt zu kommen, bildet man Klassen für diese Werte und ordnet (alle) Werte einer Klasse zu, von denen man annimmt, dass sie für den Test äquivalent sind. Dies bedeutet: Falls ein Wert einer Klasse einen (bestimmten) Fehler aufdeckt, werden dies auch alle anderen Werte dieser Klasse tun. Damit braucht nur ein einziger, beliebiger Wert aus einer Klasse für die Tests verwendet werden, womit sich die Anzahl der möglichen Testfälle stark reduzieren lässt. Kann ein testrelevanter Aspekt auch Werte annehmen, die unzulässig sind oder für die das Ergebnis nicht spezifiziert ist, so ist es wichtig, auch für diese Werte Klassen zu bilden. Ist beispielsweise für einen Eingabeparameter nur das Verhalten für die Werte 0 und 1 spezifiziert, so ist es sinnvoll auch mit anderen Werten zu testen, beispielsweise dem Wert 2.

Die Krux der Äquivalenzklassenmethode besteht darin, dass eine fehlerhafte Bildung der Äquivalenzklassen Fehler des Testobjekts unentdeckt lassen kann. Das kann passieren, wenn zwei Werte einer Klasse zugeordnet werden, wobei jedoch nur einer dieser Werte einen bestimmten Fehler aufdeckt, und für den Test der Wert verwendet wird, der den bewussten Fehler nicht aufdeckt. Trotzdem ist die Äquivalenzklassenmethode das einzig probate (und durch die ISO 26262 empfohlene) Mittel zur Reduzierung von unhandhabbar großen Mengen von Testfällen.

Grenzwertanalyse

Grenzwertanalyse (analysis of boundary values) ist eine weitere Methode aus Tabelle 11 (siehe Bild 1) zur Herleitung von Testfällen. Dem liegt die leicht einsehbare Überlegung zu Grunde, dass Testfälle mit Extremwerten und Werten an Grenzen von Bereichen fehlersensitivere Testfälle ergeben als Testfälle mit Normalwerten, denn ein fehlersensitiver Testfall deckt mit einer hohen Wahrscheinlichkeit einen Fehler auf; fehlersensitive Testfälle sind die interessanten, spannenden Testfälle.

Die Grenzwertanalyse ergibt beispielsweise Testfälle mit den größtmöglichen beziehungsweise kleinstmöglichen Eingabewerten. Soll beispielsweise geprüft werden, ob ein Wert in einem Bereich liegt, so ergibt die Grenzwertanalyse Testfälle mit Werten auf den Bereichsgrenzen, direkt vor den Bereichsgrenzen und direkt nach den Bereichsgrenzen. Anzumerken ist, dass die Grenzwertanalyse in gewissem Gegensatz zu der Äquivalenzklassenmethode steht: Die Äquivalenzklassenmethode behandelt alle Werte in einem Bereich (einer Klasse) als gleichwertig für den Test; die Grenzwertanalyse bevorzugt die Werte an den Grenzen.

Fehler raten

„Fehler raten“ ist die letzte Methode aus Tabelle 11 (siehe Bild 1) zur Herleitung von Testfällen. Hierbei wird die Erfahrung des Testfallerstellers genutzt, um fehlersensitive Testfälle zu generieren. Ist beispielsweise ein Eingabewert ein Zeiger, so wird ein erfahrener Tester sicherlich für einen Testfall mit einem NULL-Pointer sorgen, um zu prüfen, ob das Testobjekt den NULL-Pointer zum Zugriff verwenden wird (was zum Absturz des Testobjekts führen wird) oder nicht.

Die Krux dieser Methode besteht darin, dass es dauert, bis die zum erfolgreichen Einsatz der Methode notwendige Erfahrung erarbeitet ist. „Fehler raten“ ist übrigens die einzige unsystematische Methode aus Tabelle 11 (siehe Bild X1) und bietet damit die Chance, unsystematische Fehler zu finden.

Bild 2: Testfallspezifikation nach der Klassifikationsbaummethode mit dem Werkzeug CTE/ES.

Bild 2: Testfallspezifikation nach der Klassifikationsbaummethode mit dem Werkzeug CTE/ES.Hitex

Bild 2 zeigt beispielhaft eine Testfallspezifkation nach der Klassifikationsbaummethode (Classification Tree Method, CTM) für den Test einer Fahrwerksaufhängung. Im Beispiel sind die Geschwindigkeit und der Lenkwinkel die beiden testrelevanten Aspekte. Bei der Geschwindigkeit wird mit Extremwerten, beispielsweise der maximalen Geschwindigkeit v_max getestet. Bei der Geschwindigkeit erfolgt der Test auch mit ungültigen Eingaben, beispielsweise mit einer Geschwindigkeit, die größer als die Maximalgeschwindigkeit v_max ist. Ein solcher Test ist sinnvoll, wenn nicht alle möglichen Werte des Eingabeparameters gültige Geschwindigkeiten repräsentieren.

Beim testrelevanten Aspekt Lenkwinkel sieht man auf einen Blick, dass weder Extremwerte noch unzulässige Werte verwendet werden sollen. Es sei dahingestellt, ob es keine solchen Werte geben kann oder ob diese Tests vergessen wurden oder ob diese Tests absichtlich unterbleiben sollen. Wichtig ist, dass man dies leicht erkennt. Diese Visualisierung der Testabsichten ist ein wesentlicher Vorteil der Klassifikationsbaummethode. Unterhalb des Klassifikationsbaums sind zeilenweise die Testfälle spezifiziert. Anhand der Markierungspunkte in den Zeilen und der Namen der Testfälle sieht man leicht, was zu testen ist. Ein Werkzeug zur Spezifikation von Testfällen, der Classification Tree Editor CTE/ES, ist in dem Modultestwerkzeug Tessy enthalten.

Bild 3: Struktur-Überdeckungsmaße für den Software-Unit-Test. Ein einfaches Pluszeichen bedeutet „recommended“ (empfohlen), ein doppeltes Pluszeichen „highly recommended“ (in hohem Maße empfohlen).

Bild 3: Struktur-Überdeckungsmaße für den Software-Unit-Test. Ein einfaches Pluszeichen bedeutet „recommended“ (empfohlen), ein doppeltes Pluszeichen „highly recommended“ (in hohem Maße empfohlen).Hitex

Coverage

In Tabelle 12 des Teils 6 von ISO 26262 sind die Struktur-Überdeckungsmetriken für den Software-Unit-Test aufgeführt (Bild 3). In Bild 3 bedeutet ein einfaches Pluszeichen „recommended“ und ein doppelte Pluszeichen „highly recommended“.

Die Struktur-Überdeckungsmaße werden errechnet, indem man die Gesamtzahl der betreffenden Bestandteile (Anweisungen, Zweige, Bedingungen) in der Software-Unit ermittelt und diese in Beziehung setzt zu der durch die Tests ausgeführten beziehungsweise durchlaufenen Bestandteile. Ein Struktur-Überdeckungsmaß wird üblicherweise in Prozent angegeben. Um 100 % Statement-Coverage (Anweisungsüberdeckung) zu erreichen, müssen also alle Anweisungen der Software-Unit durch die Tests (mindestens ein Mal) ausgeführt werden.

Das Analoge gilt für die Branch Coverage (Zweigüberdeckung). Allerdings folgt aus 100 % Anweisungsüberdeckung nicht, dass auch alle Zweige der Software-Unit ausgeführt wurden: Der else-Teil einer if-Anweisung bildet einen Zweig – egal ob er explizit implementiert ist oder nicht. Ist er nicht explizit implementiert, so erhält man 100 % Anweisungsüberdeckung auch ohne dass die Entscheidung der if-Anweisung einmal zu false evaluiert wurde; dies reicht jedoch nicht für 100 % Zweigüberdeckung.

Die Strukturmetrik MC/DC (Modified Condition/Decision Coverage, Modifizierte Bedingungs-/Entscheidungsüberdeckung) berücksichtigt den Aufbau von Entscheidungen. Eine Entscheidung (decision) kann aus Bedingungen (conditions) aufgebaut sein, wobei die Bedingungen durch logische Operatoren (Und, Oder) verknüpft werden. Wenn man eine Entscheidung vollständig testen möchte, das heißt mit allen Kombinationen von Wahrheitswerten für alle Bedingungen, so braucht man bei n Bedingungen n2 Testfälle; es ergibt sich somit ein exponentielles Wachstum. Es gibt auch eine Überdeckungsmetrik, die alle Kombinationen erfordert; dieses heißt Mehrfach-Bedingungsüberdeckung (Multiple Condition Coverage oder Branch Condition Combination Testing). MC/DC ist so gestaltet, dass bei n Bedingungen lediglich n+1 Testfälle notwendig sind, um 100 % MC/DC zu erhalten.

Die Messung der erzielten Überdeckung und die Ermittlung der Ursachen, wenn nicht 100 % erreicht wurden, ist ein ganz wichtiger Schritt des Software-Unit-Tests. Überdeckungswerte von weniger als 100 % können auf fehlende Testfälle in Bezug auf die Anforderungen hinweisen, man kann unerreichbaren („toten“) Code und unerwünschte Funktionalität entdecken. Trotzdem muss man sich aber bewusst sein, dass beispielsweise in Software-Units ohne Entscheidungen, jedoch mit umfangreichen Berechnungen, ein einziger Testfall zur Erreichung von 100 % MC/DC reichen kann, womit die Software-Unit jedoch normalerweise nicht ausreichend getestet ist. Man muss sich deshalb hüten, das Erreichen von 100 % Überdeckung als Testende-Kriterium zu verwenden. Ferner lässt sich durch Messung der Überdeckung naturgemäß kein fehlender Code entdecken. Deshalb (und weil man den Code ja implizit schon als korrekt voraussetzt) ist es äußerst fragwürdig, Testfälle zur Erreichung einer bestimmten Überdeckung aus dem Code herzuleiten.

Software-Integrationstest

Im V-Modell der ISO 26262 in Teil 6 (Tabelle 2) ist „Software integration and testing“ der auf „Software unit testing“ folgende Prozessschritt. Hierbei werden die Software-Elemente integriert und gegen das Architekturdesign der Software geprüft (Teil 6, Abschnitt 10.1). Die Softwareelemente kann man sich hierzu als die Software-Units vorstellen, die zu größeren Einheiten zusammengefasst werden, um ihr Zusammenspiel an den Schnittstellen zwischen ihnen zu testen. Eine solche Ansammlung aus einer oder mehreren Software-Units bezeichnet die ISO 26262 auch als Komponente (Teil 1, Abschnitt 1.15). Deshalb nennen wir das Testobjekt des Software-Integrationstests eine Komponente.

Bild 4: Komponente als Testobjekt für den Software-Integrationstest.

Bild 4: Komponente als Testobjekt für den Software-Integrationstest.Hitex

In Bild 4 ist eine Komponente, das Testobjekt für den Software-Integrationstest, schematisch dargestellt. Die kleinen Quadrate symbolsieren Software-Units und damit Funktionen im Sinne von C, wobei unterschieden wird zwischen Units, die außerhalb der Komponente sichtbar sind und deshalb von außerhalb der Komponente aufgerufen werden können (dunkelblau), und solchen Units, die nach außen nicht sichtbar sind (hellblau). Die Units in einer Komponente müssen nicht notwendigerweise in einer Aufrufhierarchie stehen.

Durch Aufruf der von außen sichtbaren Units wird die Komponente stimuliert; ein Testfall für eine Komponente ist also allgemein eine Sequenz von Aufrufen dieser Units. Dies symbolisieren die grünen Pfeile. Normalerweise wird eine Sequenz aus Aufrufen unterschiedlicher Units bestehen – ein wesentlicher Unterschied zum Unit-Test, bei dem immer ein und dieselbe Unit zum Test aufgerufen wird, wenn auch möglicherweise mehrfach hintereinander. Falls beim Unit-Test eine zu testende Unit eine andere Unit aufruft und für den Test diese aufgerufene Unit tatsächlich zum Einsatz kommt, hat man eigentlich schon eine Komponente als Testobjekt und führt einen Software-Integrationstest durch, denn das Testobjekt ist aus zwei Units zusammengesetzt, und diese werden integriert (in ihrem Zusammenspiel) getestet. Es wird jedoch für den Test ausschließlich die aufrufende Unit stimuliert.

Eine Unit kann auch Daten enthalten, auf die vor, während und nach der Ausführung eines Komponenten-Testfalls zugegriffen werden kann (lesend zum Überprüfen von Werten und schreibend zum Setzen von Werten). Dies symbolisieren der schraffierte Bereich und der schraffierte Doppelpfeil. Da eine Komponente nicht die gesamte Applikation umfasst, werden normalerweise auch Units für den Test benötigt, die sich nicht innerhalb der Komponente befinden. Dies symbolisieren die beiden roten Pfeile. Während des Tests werden diese benötigten Units üblicherweise (als sogenannte Stub-Funktionen) durch Tessy bereitgestellt, und es kann in das Testergebnis eingehen, ob, wie oft, mit welchen Parametern und in welcher Reihenfolge solche Units aufgerufen wurden.

Ein einfaches Beispiel für zwei Units, die zu einer Komponente integriert getestet werden sollten, sind die Operationen push() und pop() des abstrakten Datentyps „Stack“.

Tool Qualification

ISO 26262 fordert in Teil 8, Abschnitt 11, das Niveau des Vertrauens in ein verwendetes Software-Werkzeug zu bestimmen. Für das Werkzeug Tessy wurde der Tool Confidence Level (TCL) 3 ermittelt. Ferner wurde Tessy vom TÜV Süd qualifiziert zum Einsatz bei sicherheitskritischer Softwareentwicklung nach ISO 26262 vorqualifiziert. Zugehörige Dokumente und ein Tool Qualification Package für Tessy stehen zur Verfügung und helfen bei der Qualifizierung von Tessy für ein bestimmtes Anwenderprojekt.