Testen von Embedded Software

Optimierte Unit-Tests für sicherheitskritische Systeme

10. Oktober 2022, 6:00 Uhr | Ricardo Camacho
Asian team Outsource Developer Looking Screen Programming Code Working with Laptop Computer Software.
© snowing12 – stock.adobe.com

Mit einigen Schlüsselelementen lassen sich Unit-Tests so optimieren, dass sie über das gesamte Projekt und die gesamte Unternehmensstruktur skalierbar sind. Beim Entwerfen, Entwickeln und Pflegen der Tests können alle Mitglieder des Software-Teams ihre Erfahrungen einbringen.

Unit-Tests sind eine grundlegende Software-Praxis und können – bei richtiger Durchführung – die Geschwindigkeit und Qualität der Softwareentwicklung erhöhen und gleichzeitig das Risiko und die Gesamtkosten senken. Bei sicherheitskritischen Systemen sind Unit-Tests nicht nur notwendig, um die Software für den vorgesehenen Einsatz zu qualifizieren, sondern sie sind auch ein Eckpfeiler der Sicherheit während der Verifizierung und Validierung. Leider sind Unit-Tests sehr zeit- und ressourcenaufwändig. In der Regel wird jemand mit Programmierkenntnissen benötigt, um Unit-Tests zu entwerfen, zu entwickeln und zu pflegen. Einmal geschriebene Unit-Tests sind zudem anfällig für Änderungen an der Software, und die Wartung erschwert das Projekt insgesamt.

Anbieter zum Thema

zu Matchmaker+

Am Anfang steht die Testerstellung

Ohne die Hilfe von Automatisierungstools ist das Erstellen von Unit-Tests ein langwieriger und zeitraubender Prozess. Denn sie müssen von Softwareingenieuren programmiert werden, die sowohl mit der zu testenden Einheit als auch mit der gesamten Entwicklungs- und Ausführungsumgebung vertraut sind. Moderne Testautomatisierungstools wie C/C++test von Parasoft verringern diese Komplexität, indem sie direkt in die IDE des Entwicklers integriert werden – z.B. in Visual Studio oder Eclipse-basierte IDEs – und ein Framework bieten, das bei der Erstellung und Ausführung von automatisierten Unit-Tests unterstützt.

Eine der Herausforderungen bei der Einführung eines Automatisierungstools, um Unit-Tests zu unterstützen, ist der Mix aus Fähigkeiten und Vorlieben der Teammitglieder. Einige wollen tief und direkt in den Code einsteigen, manche ohne Verwendung einer IDE, andere wollen auf einer höheren Ebene bleiben und sich auf Testlogik und Parametrisierung konzentrieren. Die Lösung liegt in der Verwendung geeigneter grafischer Editoren und Ansichten, zusammen mit Quellcode-basierten Darstellungen der Testartefakte, wie Testfälle und Stubs.

Dadurch können erfahrene Entwickler ihre Testfälle schnell mit Hilfe von quellcodebasierten APIs erstellen, und zugleich andere Teammitglieder, z.B. Test-/QA-Ingenieure, den Prozess der Testerstellung mit grafischen Editoren erweitern. C/C++test beispielsweise bietet einen Testeditor, der die Interaktionen der Benutzeroberfläche erfasst und Quelltests erstellt, die im Quellcode beibehalten oder als UI-gesteuerte Tests gepflegt werden können. So bestimmt das Team selbst, wie es Tests am besten erstellt, erweitert und verwaltet.

UI-gestützte Erstellung von Testfällen.
Bild 1. UI-gestützte Erstellung von Testfällen.
© Parasoft

Es hat Vorteile, wenn die Testfälle als Quellcode gespeichert und die Werte für die getesteten Codeparameter im Quellcode initialisiert werden. Weil diese Strategie dem Prozess der Parameter-Initialisierung im Produktionscode sehr viel näher kommt, eignet sie sich besser zum Testen von sicherheitskritischem Code, insbesondere bei Embedded-Geräten.

Testfall mit quellcodebasierten APIs.
Bild 2. Testfall mit quellcodebasierten APIs.
© Parasoft

Bei vielen Embedded-Entwicklungsprojekten müssen die Testartefakte so weit wie möglich mit dem Code übereinstimmen, der auf dem Gerät und auf dem beabsichtigten Ziel ausgeführt werden soll, anstatt nur Host-basierte Tests durchzuführen.

Isolieren von Komponenten zum Verbessern der Automatisierung

Unit-Tests verlangen viel mehr als nur ein Testprogramm zum Ausführen und Abrufen von Ergebnissen aus der zu testenden Unit. Der schwierigste Teil besteht darin, eine Einheit von ihren externen Abhängigkeiten zu isolieren, so dass nur die Einheit selbst getestet wird. Dies erleichtert eine stabile Automatisierung. Wird ein Problem gefunden, weiß man, dass das Problem in der Unit liegt und nicht irgendwo in einer ihrer Abhängigkeiten versteckt ist. Zur Isolierung von Einheiten kommen Stubs oder Mocks – manchmal auch Testdoubles genannt – zum Einsatz, aber die Programmierung und Kontrolle der Antwort von Stubs kann sich aufwändig gestalten.

Die Schwierigkeit, das getestete System zu simulieren, hängt davon ab, wie gut der Code entwickelt wurde, damit er testbar ist, und wie kompliziert seine Interaktionen mit der Außenwelt sind. Ein Stub oder Mock, der einen Hardware-Funktionsaufruf emulieren soll, muss beispielsweise während des Testprozesses mit vernünftigen Werten reagieren und könnte einfach fest codierte Werte verwenden oder muss Testdaten dynamisch aus einer externen Datenquelle lesen.

Flexible Stubbing-Optionen

Bei C/C++test ist das Stubbing von Abhängigkeiten der bevorzugte Ansatz für die Code-Isolierung. Im Gegensatz zu Mocking-Frameworks muss bei Stubs der Code nicht umgestaltet werden und es wird keine spezielle Code-Struktur – z.B. virtuelle Funktionen – benötigt, um sie anzuwenden.

Stubs als Callbacks einzusetzen ermöglicht das einfache Verbinden von Tests und Stubs, ein globales Stubbing-Framework dagegen kann zur Ausführungszeit rekonfiguriert werden, um Flexibilität zwischen gestubbter Funktion und echtem Code zu ermöglichen, wie es bei Integrationstests der Fall ist. Das bedeutet, dass dieselben Testfälle sowohl im Isolations- als auch im Integrationsmodus verifiziert, und die Ergebnisse auf mögliche Unterschiede hin verglichen werden können. Die Änderung des Testmodus ist ein einfacher Vorgang und setzt nur die Angabe des neuen Standorts der Stubsuite voraus.

Testausführung

Bei einigen Anwendungen ist die Testausführung kein Problem, da die Tests auf dem Entwicklungsrechner ausgeführt und die Ergebnisse gesammelt werden können. Bei Embedded-Systemen, und insbesondere bei sicherheitskritischen Systemen, müssen die Tests auf dem vorgesehenen Zielsystem ausgeführt werden. Dabei kann das Zielsystem eine völlig andere Architektur haben als ein typisches Desktop-System, mit einem anderen Betriebssystem und anderen Leistungsmerkmalen.

Zielgerichtete Hardware-Tests.
Bild 3. Zielgerichtete Hardware-Tests.
© Parasoft

Die manuelle Testausführung auf Embedded-Zielsystemen ist eine weitere zeitaufwändige Aufgabe – hier bedeutet die Testautomatisierung große Erleichterung, sei es lokal oder auf einem entfernten Zielsystem. Bei modernen Testprogrammen wie C/C++test beinhaltet die Remote-Ausführung zudem die Laufzeitanalyse, das Erfassen der Codeabdeckung und Extrahieren der Testergebnisse. Das Blockdiagramm in Bild 3 veranschaulicht die lokale und ferngesteuerte Testausführung in C/C++test.


  1. Optimierte Unit-Tests für sicherheitskritische Systeme
  2. Wann ist das Testen abgeschlossen?
  3. Alles bündeln: Innovative Berichterstattung und Analytik

Verwandte Artikel

Parasoft, Parasoft Corp.