Zum Inhalt springen

Suchen...

Implementierung als Testorakel

Wer Sollwerte für 2.500 Signale manuell berechnet, verliert den Anschluss. Wie eine Referenzimplementierung als Testorakel das löst.

7 Min. Lesezeit
Cover für Implementierung als Testorakel

Eine Referenzimplementierung als Testorakel bedeutet: Der Tester implementiert dieselbe Funktionalität unabhängig vom Entwickler in einer einfachen Hochsprache wie Python oder Matlab. Beide Ergebnisse werden per Back-to-Back-Test verglichen. Das ersetzt manuelle Sollwertberechnung, vereinfacht Reviews auf Code-Ebene und skaliert selbst bei tausenden Signalen.

Das Wichtigste in Kürze

  • Eine Referenzimplementierung als Testorakel bedeutet, dass der Tester die Software unabhängig vom Entwickler nochmals nachbaut und beide Versionen im Back-to-Back-Test verglichen werden.
  • Tester dürfen beim Erstellen der Referenzimplementierung keinen Zugriff auf den Originalquellcode haben, damit Codierfehler des Entwicklers nicht unbewusst übernommen werden.
  • Das Review einer Referenzimplementierung ist ein strukturiertes Code-Review mit Checkliste, was gegenüber dem manuellen Nachrechnen von Sollwerten deutlich weniger Aufwand erzeugt.
  • Automatisch generierte Stimuli für strukturbasierte Code-Coverage lassen sich gegen die Referenzimplementierung laufen, um auch die letzten fehlenden Prozentpunkte abzusichern, ohne eine selbsterfüllende Prophezeiung zu erzeugen.
  • Anforderungsänderungen erfordern bei diesem Ansatz nur eine Codeänderung an einer Stelle der Referenzimplementierung statt manuelle Anpassungen an Dutzenden von Sollwerten in Testfällen.

Was ist ein Pseudo-Testorakel mit Referenzimplementierung?

Ein Pseudo-Testorakel mit Referenzimplementierung ist ein Testansatz, bei dem der Tester die zu prüfende Funktion ein zweites Mal nachbaut: unabhängig vom Entwickler, in vereinfachter Form. Diese Nachbildung dient als Vergleichsmaßstab. Die ausgelieferte Software und die Referenzimplementierung laufen über dieselben Eingangsdaten, und ihre Ausgaben werden gegeneinander geprüft.

Der Entwickler implementiert seinen produktiven Code, der später ins Fahrzeug geht. Der Tester implementiert dieselbe Logik parallel, aber in einer einfachen Hochsprache wie Python oder Matlab Script. Stimmen die Ausgaben beider Implementierungen überein, gilt das Verhalten als spezifikationskonform.

Stefanie Leitner arbeitet bei einem Automobilzulieferer im Volkswagen-Konzern, der Embedded Software für autonomes Fahren und Fahrzeugsicherheit entwickelt. Dort wird dieser Ansatz seit über zehn Jahren eingesetzt, um komplexe sicherheitskritische Funktionen wie Spurhalte- und Notbremsassistenten zu testen.

Warum manuelle Sollwerte bei hoher Komplexität nicht mehr funktionieren

Manuelles Berechnen von Sollwerten skaliert nicht, sobald die Zahl der zu prüfenden Signale in die Tausende geht. Genau hier setzt das Problem an, das die Referenzimplementierung löst.

Allein die ersten Softwarekomponenten, die eingehende Bussignale verifizieren, prüfen nicht 10 oder 20 Signale, sondern 2500 bis 3000. Format, Gültigkeit und Wertebereich müssen für jedes davon stimmen. Wer diese Sollwerte von Hand berechnet, kommt nicht hinterher. Ändert sich eine Kleinigkeit, hängt der Test fest und kann kein frühes Feedback liefern.

Der zweite Treiber sind die Algorithmen selbst. Die Trajektorienberechnung im autonomen Fahren, etwa die Frage, ob die Spur frei ist und ein Ausweichmanöver möglich, besteht aus vielen aufeinanderfolgenden Rechenschritten. Für jeden Testschritt müsste der Tester den erwarteten Wert einzeln ermitteln. Beide Probleme führten zur selben Lösung: ein automatisiertes Orakel, das die Sollwerte berechnet, statt sie händisch vorzugeben.

Wie die Referenzimplementierung im Detail aufgebaut ist

Die Referenzimplementierung bildet die volle Logik der Funktion ab, nicht nur einen Dummy. Am Ende steht ein Back-to-Back-Test, der die Originalsoftware Signal für Signal gegen die Nachbildung vergleicht.

Anders als der produktive Code muss die Referenzimplementierung nicht den kompletten Entwicklungsprozess durchlaufen. Codier-Richtlinien spielen keine Rolle, ebenso wenig die Optimierung auf Ressourcen, weil der Code nie ins Fahrzeug geht. Bibliotheken in Python liefern viele Funktionen fertig mit, was die Umsetzung beschleunigt.

Damit der Ansatz trägt, gelten feste Regeln:

  • Unabhängigkeit: Entwickler und Tester müssen zwei verschiedene Personen sein. Niemand baut sein eigenes Modell und prüft es dann gegen sich selbst.
  • Kein Zugriff auf den Originalcode: Die Tester sehen den produktiven Quellcode zum Zeitpunkt der Implementierung nicht. So wird vermieden, dass sie Lösungsansätze abschauen oder denselben Codierfehler reproduzieren.
  • Traceability: Wie im Originalcode werden auch in der Referenzimplementierung die Anforderungen verlinkt. Das macht Vollständigkeit prüfbar und hilft, die Konsistenz zur Spezifikation zu sichern.

Die Größe der Referenzimplementierung richtet sich nach der jeweiligen Unit, typisch zwischen 100 und 1000 Zeilen. Auf Unit-Ebene wird sie bewusst klein gehalten.

Das Review wird vom Rechenmarathon zum Code-Review

Der größte Alltagsgewinn liegt im Review. Wo Prüfer früher jeden manuell berechneten Sollwert nachrechnen mussten, wird daraus jetzt ein Code-Review mit Checkliste.

Die ISO 26262 verlangt ab ASIL B eine Inspektion der Testfälle. Beim klassischen Vorgehen bedeutete das, sämtliche von Hand ermittelten Werte ein zweites Mal durchzurechnen: aufwendig und fehleranfällig. Mit der Referenzimplementierung prüft der Reviewer stattdessen den Code, kann über die verlinkten Anforderungen nachvollziehen, ob der Tester sie richtig interpretiert hat, und stellt so Vollständigkeit und Konsistenz sicher.

Wie hart dieser Vorteil wiegt, zeigte ein Projekt, in dem ein Projektleiter den Aufwand scheute und auf das klassische Vorgehen mit Skripten zurückging. Spätestens beim Review jammerten alle. Die Lehre daraus war eindeutig: nie wieder so.

Entwickler und Tester starten parallel, nicht nacheinander

Sobald die Anforderungen freigegeben sind, beginnen Entwickler und Tester gleichzeitig. Der eine implementiert die produktive Software und seine Entwicklertests, der andere die Referenzimplementierung und die Testfallspezifikation.

Davor steht ein doppeltes Review der Anforderungen, einmal aus Entwickler-, einmal aus Testersicht. Vieles an Unschärfe wird hier schon abgefangen. Im Idealfall werden beide Seiten zeitgleich fertig und können direkt in die Testausführung gehen.

Schlägt der Vergleich später fehl, stellt sich die Frage, auf welcher Seite der Fehler sitzt. Die Vorgabe: Der Tester prüft zuerst seine eigene Referenzimplementierung. Erst wenn er sicher ist, dass sie sich wie spezifiziert verhält, geht ein Fehler-Ticket an den Entwickler, der die Software debuggt.

Der echte Nutzen liegt in Testtiefe und Wartbarkeit

Der Ansatz vergleicht zu jedem Zeitpunkt jedes Ausgangssignal, nicht nur die wenigen Signale im Scope einer einzelnen Anforderung. Das hebt die Testtiefe deutlich.

Genutzt wird das vor allem auf Unit- und Integrationstestebene. Weil zu jedem Testschritt für jedes Signal ein Wert vorliegt, tauchen Rand- und Seiteneffekte auf, die man bei einer reinen Betrachtung der spezifizierten Ausgabesignale übersehen hätte.

Auch bei Änderungen zahlt sich das aus. Ändert sich eine Anforderung, reicht oft eine Zeile im Referenzcode, etwa ein größer-gleich statt eines größer. Nach dem Back-to-Back-Test sind die Sollwerte aktualisiert, ohne dass jemand 60 erwartete Werte in den Testfällen von Hand anpassen muss. Varianten, Kodierung und Kalibrierdaten lassen sich direkt mitprogrammieren: Datensatz tauschen, fertig.

Ein weiterer Effekt zeigte sich bei der strukturbasierten Coverage. Gefordert sind ab ASIL B Decision Coverage, ab ASIL C MCDC. Die letzten fünf Prozent bis zur vollen Abdeckung sind für Tester knifflig.

Wenn du den Sollwert generierst, ist das eine selbsterfüllende Prophezeiung. Aber wir haben ja unsere Referenzimplementierung. Wir nehmen die Stimuli, lassen sie über die Referenzimplementierung laufen und bekommen so auch für die letzten fünf Prozent, ob die Software sich verhält, wie sie soll.

Stefanie Leitner

Das Tool generiert dabei nur die Stimuli aus dem Code. Die Sollwerte kommen aus der Referenzimplementierung, sonst würde sich der Code selbst bestätigen.

Anfangsskepsis im Team: Liegt der Fehler im Code oder im Modell?

Die größte Hürde ist nicht technisch, sondern eine Vertrauensfrage. Anfangs zweifeln Entwickler, ob ein gemeldeter Fehler wirklich in ihrer Software liegt oder doch im Referenzmodell.

Diese Skepsis lässt sich nur durch die vorgeschalteten Mechanismen auflösen: unabhängige Implementierung, Review, Traceability. Jeder macht Fehler, und gelegentlich rutscht etwas durch. Doch in der Praxis trägt der Vergleich, und im Zweifel schauen beide gemeinsam in die Referenzimplementierung. Oft klärt sich dann, dass jemand die Anforderung anders verstanden oder im Code etwas vergessen hat.

Für die Entwickler hat die Referenzimplementierung sogar einen Nebennutzen beim Debuggen. Sie sehen, wie der Tester die Anforderung gelöst hat, und erkennen schneller, wer von beiden sie nicht wie gemeint umgesetzt hat.

Welche Skills Tester für diesen Ansatz brauchen

Tester müssen entwickeln können, aber kein Spezialwissen mitbringen. Grundlagen der Programmierung wie Schleifen reichen als Basis, der Rest lässt sich lernen.

Viele Tester im Embedded-Umfeld kommen ohnehin aus der Informatik, die Grundlagen sind also da. Python und Matlab Scripting bereiteten bislang keine Probleme und ließen sich über interne Trainings vermitteln. Statt strenger Codierstandards gibt es ein Template und ein paar Guidelines, vor allem für die Traceability. So findet sich ein Tester schnell in der Arbeit eines anderen zurecht, wenn jemand ausfällt.

Wann sich der Aufwand nicht lohnt

Nicht jede Funktion verdient eine Referenzimplementierung. Bei sehr einfachen Units mit nur wenigen mathematischen Berechnungen steht der Aufwand oft in keinem Verhältnis zum Nutzen.

Deshalb gibt es Kriterien dafür, wann der Ansatz sinnvoll ist und wann nicht. Diese Kriterien sollen weiter geschärft werden. Zugleich wird geprüft, ob KI die Erstellung der Referenzimplementierung beschleunigen kann, sodass sich auch in Grenzfällen die Schwelle verschiebt.

Häufig gestellte Fragen

Eine Referenzimplementierung als Testorakel ist ein zuverlässiges Referenzmodell, das im Software-Testprozess verwendet wird, um die Korrektheit von Entwicklercode durch automatisierte Testfälle zu überprüfen und Fehler zu identifizieren.

Die Referenzimplementierung dient als Testoracle, das Testfälle automatisiert ausführt und den Entwicklercode mit dem Referenzmodell vergleicht, um Abweichungen zu erkennen und die Qualitätssicherung zu verbessern.

Der Einsatz eines Referenzmodells ermöglicht eine automatisierte Fehlererkennung, steigert die Effizienz bei der Fehlerbehebung und erhöht insgesamt die Produktivität durch optimierte Testabläufe.

Das Referenzmodell wird in der Softwareentwicklung zur Codeüberprüfung genutzt, unterstützt die Traceability zwischen Anforderungen und Implementierung und fungiert als Testorakel zur Sicherstellung der Softwarequalität.

Zukünftige Entwicklungen umfassen die Integration von KI-Unterstützung zur Optimierung von Testverfahren sowie die Weiterentwicklung des Referenzmodells, um aktuellen und zukünftigen Anforderungen im Software-Testing gerecht zu werden.

KI und neue Technologien ermöglichen eine verbesserte Automatisierung und Optimierung des Testprozesses, wodurch die Rolle von Referenzimplementierungen als Testorakel gestärkt wird und die Qualitätssicherung effizienter gestaltet werden kann.

Diese Seite teilen

Ähnliche Beiträge