
System-/Integrations-Tests von Embedded Devices: Wann ist eine Automatisierung sinnvoll?
Einführung
Die Verifizierung der Funktionalität eines ganzheitlichen Produkts ist ein wichtiger Bestandteil der Produktentwicklung.
Im Fall eines Produkts, welches aus Hard- und Softwarekomponenten besteht, wird diese Verifizierung häufig manuell durchgeführt. Automatisierte System- und Integrationstests mit Hardware-in-the-Loop (HIL) können eine Entlastung bringen und stellen einen wichtigen Bestandteil der Testing Trophy dar (siehe Beitrag zur Testing Trophy).
In diesem Artikel möchten wir auf die Gründe für solche automatisierten Tests eingehen sowie auf einige wichtige Aspekte, die beachtet werden sollten, um den maximalen Nutzen aus diesen Tests zu ziehen. Spezifische Technologien werden jedoch nicht im Detail behandelt.
In welchen Entwicklungsphasen sollten automatisierte Tests verwendet werden?
Verifikation
Niemand verbringt gerne Zeit damit, unzählige Tests manuell bei jeder neuen Software-Version auszuführen. Der Gedanke «Wieso automatisieren wir diesen Vorgang nicht einfach?» liegt daher nahe. Wer jedoch hofft, dadurch kurzfristig Zeit einzusparen, wird unserer Erfahrung nach enttäuscht.
In vielen Projekten wird der Aufwand, eine vollständige und nachhaltige Testumgebung zu entwickeln und zu pflegen, den Aufwand der manuellen Testdurchführung bei Weitem übersteigen.
Um diesen Aufwand zu rechtfertigen ist es daher wichtig, dass die Testumgebung auch ausserhalb der Verifikation verwendet wird, insbesondere in den folgenden zwei Anwendungsfällen:
Regressionstests
Das frühe Erkennen einer Regression (eine bestehende Funktion verhält sich nicht mehr wie gewünscht nach der Einführung einer neuen, unabhängigen Funktion) ist Gold wert.
Zum einen lässt sich ein Fehler mit viel weniger Aufwand beheben, wenn dem Entwickler bekannt ist, durch welche Änderungen dieser entstanden ist.
Zum anderen wird das Risiko für Überraschungen während der Schlussverifikation erheblich reduziert und zusätzliche Verifikationsrunden werden vermieden.
Eine Auswahl der vorhandenen Tests sollten daher bei jedem Pull-/Merge-Request ausgeführt werden.
Dazu folgende Tipps:
- Um den Entwicklungsprozess nicht unnötig zu verlangsamen, sollten diese Tests in nur wenigen Minuten durchlaufen.
- Testdurchläufe über Nacht oder am Wochenende sorgen dafür, dass regelmässig alle Tests ausgeführt werden.
- Eine frühzeitige Kategorisierung der Tests erleichtert es, nachträglich zu entscheiden, welche Tests in welcher Stufe ausgeführt werden.
Unterstützung im Entwicklungsprozess
Im besten Fall wird das Testframework während des Entwicklungsprozesses verwendet, um neue Funktionalitäten parallel zur Implementierung zu testen.
Häufig ist die Softwarearchitektur in verschiedene Module aufgeteilt, was zu einer Aufteilung der Arbeiten führt. Zuerst werden ein oder mehrere Low-Level-Module entwickelt und anschliessend werden diese durch eine/n weiteren Entwickler/in in ein oder mehrere High-Level-Module integriert.
Doch wie wird ein solches Low-Level-Modul getestet, bevor es verwendet wird?
Unit-Tests allein reichen häufig nicht aus, da hierbei die Hardware ignoriert wird. Ohne die Möglichkeit automatisierte Integrationstests zu schreiben, wird häufig temporärer Testcode verwendet. Dieser Testcode wird an einer beliebigen Stelle in der Applikation eingeführt (z.B. direkt im main) und nach Abschluss der Implementierung wieder entfernt.
Die komplette Funktionalität (Integration von Low- und High-Level-Modulen), wird durch manuelle Manipulation des DUTs (Device Under Test) getestet.
Diese beiden Arbeitsabläufe können durch automatisierte Integrations-/Systemtests optimiert werden.
Ein durchdachtes Testframework macht es attraktiv, die Tests direkt während der Implementierung zu schreiben. Temporärer Testcode weicht Integrationstests, die dauerhaft abgelegt werden. Anstatt das DUT immer wieder manuell zu testen, werden entsprechende System-/Integrationstests geschrieben.
Blackbox-Tests können anhand der Spezifikation von einer Drittperson implementiert werden. Sind die Spezifikationen nicht ausreichend, um ein Modul/System zu definieren, kann auf Whitebox-Tests zurückgegriffen werden. Diese können während der Feature-Implementierung vom gleichen Entwickler geschrieben werden und sorgen für eine hohe Testabdeckung.
Anforderungen an ein Testframework
Stabilität
Die Stabilität der automatisierten Tests ist eine besonders wichtige und auch eine der aufwändigsten Anforderungen. Fehlerquellen sind zahlreich vorhanden. Ein Firmware-Upload funktioniert nicht, ein Verbindungsproblem mit USB tritt auf, ein Update auf dem Test-Host verursacht Probleme, Änderungen in Timings stören die Tests etc.
Wenn die Tests nicht stabil genug sind, schlagen während der Verifikation immer wieder Tests fehl.
Mit der Begründung: "Normalerweise funktioniert der Test" werden diese wiederholt, bis das Ergebnis den Erwartungen entspricht.
Bei Regressionstests verliert das Entwicklungsteam das Vertrauen und Interesse an den Testresultaten. Fehler werden abgetan als:
«Bestimmt wieder ein Problem beim Verbindungsaufbau mit dem DUT» etc.
Neue Fehler werden ignoriert und die Anzahl der fehlerhaften Tests nimmt kontinuierlich zu.
Testlaufzeit
Eine geringe Testlaufzeit erlaubt es, mehr Tests in einem Pullrequest oder über Nacht auszuführen.
Eine kurze Testlaufzeit wirkt sich positiv auf die Motivation aus, das Testframework während der Entwicklung zu nutzen.
Wenn das manuelle Ausführen der Tests schneller ist, werden sich Entwickler/innen dagegen sträuben, Tests zu implementieren und diese stattdessen manuell durchführen.
Verwendbarkeit
Ein Testframework, das es einem/einer Entwickler/in erlaubt seine Tests schnell und einfach zu implementieren, wird auch gerne genutzt.
Ist es hingegen umständlich, etwas automatisiert zu testen, greift der/die Entwickler/in schnell auf manuelle Tests zurück.
Testabdeckung
Eine hohe Testabdeckung durch automatisierte Tests ist erstrebenswert, da alle Teile der Software, die nicht automatisiert getestet werden, manuell verifiziert werden müssen.
Lösungsansätze
Test Setup
Ein ausführliches Setup stellt sicher, dass sich das DUT (Device Under Test) vor jedem Test immer im gleichen Zustand befindet.
Zu den möglichen Aufgaben gehören:
- Überprüfung der Firmware
- Neustarten des DUT
- Zurücksetzten der Datenbank
- Messen des Batteriezustands
- Zurücksetzten des Fehlerlogs
- Rückführung von Motoren, etc.
Ein solch ausführliches Setup erhöht die Stabilität der Tests, hat jedoch einen negativen Einfluss auf die Testlaufzeit.
Ein zweites, schnelleres und weniger ausführliches Setup kann als Kompromiss dienen. Dieses Setup könnte für die Ausführung während des Entwicklungsprozesses ausreichen, da hier eine kurze Testlaufzeit wichtiger ist als maximale Stabilität.
Besonders wichtig ist, dass das Setup unter allen Umständen funktionieren muss. Fehlerhafte Software kann das DUT in unerwünschte Zustände versetzen. Der Test-Host muss auch in solchen Situationen in der Lage sein, eine neue Firmware herunterzuladen und gegebenenfalls die Datenbank wiederherzustellen.
Automatisierte Ansteuerung der Hardware
Mit genügend Sensoren, Aktoren und sonstiger Mechanik lässt sich so gut wie alles automatisieren. Eine solche Automatisierung ist jedoch mit viel Aufwand verbunden.
Zudem wird die Stabilität der Tests leiden.
Beispielsweise kann eine Kamera eingesetzt werden, um die Anzeige des Displays zu kontrollieren. Ein weiteres Gerät bedeutet aber auch eine weitere Quelle für Störungen. (Verbindungprobleme, Abstürze der Kamerafirmware oder der PC-Software).
Durch einen kurzen Verbindungsverlust oder kurze Verzögerungen, gehen möglicherweise Informationen verloren. Z.B. ein Pop-Up wird nicht erkannt und der Test schlägt fehl.
Hier sollte genau abgewogen werden, ob und wo es sich lohnt, eine solche Automatisierung einzuführen.
- Kann ausschliesslich durch eine Automatisierung der Hardware, eine kritische Stelle der Software getestet werden, oder existieren Alternativen?
- Können aufwändige manuelle Tests durch automatisierte ersetzt und dadurch Zeit gewonnen werden?
Kommunikationsschnittstelle
Die gewählte Kommunikationsschnittstelle zwischen Test-Host und DUT muss eine hohe Zuverlässigkeit besitzen. Probleme bei der Schnittstelle sind erfahrungsgemäss eine der grössten Ursachen bei instabilen Tests.
Um die Stabilität der Kommunikationsschnittstelle zu verbessern, sollten alle Verbindungen kabelgebunden sein. Selbst bei drahtlosen Verbindungen (z.B. Bluetooth) sollte nach Möglichkeit ein Kabel anstelle einer Antenne verwendet werden.
Die Architektur der Schnittstelle und des verwendeten Protokolls hat einen der grössten Einflüsse darauf, wie gut sich das ganze Testframework verwenden lässt.
Je mehr Möglichkeiten der/die Testentwickler/in hat das DUT zu steuern und auszuwerten, umso einfacher wird es, die Tests bei der Entwicklung zu schreiben.
Daher bietet es sich an, eine Schnittstelle zu implementieren, welche ausschliesslich zum Testen verwendet wird.
Beispielfunktionen eines solchen Protokolls:
- Auslösen von Ereignissen in beliebigen Softwarekomponenten
- Aufrufen beliebiger Funktionen
- Laden/Anpassen verschiedener Konfigurationen
- Benachrichtigungen über Zustandsänderungen
- Auslesen beliebiger Variablen
Wird eine dedizierte Test-Schnittstelle eingesetzt, muss diese gegen unbefugten Zugriff geschützt werden. Es ist nicht empfehlenswert, die Schnittstelle komplett aus einem Software-Release zu entfernen. Ansonsten wird eine spezielle Testsoftware benötigt und die Tests werden nicht auf dem eigentlichen Software-Release aufgeführt.
Wird eine solche Test-Schnittstelle verwendet, dann wird das DUT nicht auf dieselbe Weise getestet, wie es von einem User verwendet wird. Daher sollten einige manuelle Tests als Ergänzung durchgeführt werden.
Monitoring
Ein Informationsaustausch zwischen DUT and Test-Host kann alternativ, zu aufwändiger automatisierter Hardwareansteuerung/-auswertung, schon ausreichen.
Beispielsweise für das Testen eines DUTs mit einem Display.
Auf Anfrage werden die Events für die Darstellung der verschiedenen Anzeigen nicht nur an das Display-Software-Modul weitergeleitet, sondern auch an den Test-Host.
Dadurch kann verifiziert werden, dass die korrekten Anfragen beim Display ausgelöst werden. Die Korrektheit der Anzeige muss jedoch bei einer Verifikation durch eine manuelle Testdurchführung festgestellt werden.
Man gewinnt somit Stabilität und spart sich viel Aufwand für den Preis, dass alle möglichen Anzeigen manuell überprüft werden müssen.
Praxisbeispiel

Abbildung 1: Block Diagramm Beispiel
Das DUT setzt sich aus zwei Hardware-Komponenten zusammen. Ein proprietärer Radio-SoC, welcher simple Funktionalitäten zur Verfügung stellt wie Verbindungsaufbau und Datenaustausch. Ein Mikrocontroller wird eingesetzt für die Steuerung des Radio-SoC, Benutzerinterfaces, Batteriemanagement etc.
Mehrere dieser Geräte können kabellos zu einem Netzwerk zusammengeschlossen werden.
Die Integrationstests in diesem Beispiel fokussieren sich auf das Testen der Radio-Controllers, welcher für die Ansteuerung des Radio-SoCs zuständig ist. Ausführliche Tests sind für diese Softwarekomponente besonders wichtig, da es sich hierbei um einen sehr komplexen Teil der Firmware handelt.
Die Testapplikation ist in Python geschrieben und wird auf dem Test-Host ausgeführt. Der Radio-Controller, welcher normalerweise auf dem Mikrocontroller läuft, wird auch auf dem Test-Host ausgeführt. Einzig der Radio-SoC ist mit originaler Hardware und Firmware im Testsystem eingebunden.
Die Kommunikation zwischen Testapplikation und Radio-Controller erfolgt über Remote Python Call (RPyC), und verwendet dieselben Methoden/Klassen wie die eigentliche Firmware. Die Antenne wird durch eine kabelgebundene Verbindung ersetzt.
Ein solcher Testaufbau hat diverse Vorteile:
- Python erlaubt schnelle Implementation der Testapplikation. Langes kompilieren entfällt.
- Da der zu testende Radio-Controller auf dem Host ausgeführt wird, verringert sich die Setup-Zeit vor jedem Testdurchlauf, da das Herunterladen der Firmware entfällt.
- Das Weglassen des Mikrocontrollers eliminiert eine Fehlerquelle und führt zu stabileren Tests.
- Die kabelgebundene Verbindung zwischen den Radio-SoCs verringert Störungen und sorgt für stabilere Tests.
- Neue Funktionalitäten für den Radio-Controller können implementiert und getestet werden, bevor diese in die restliche Applikation des Mikrocontrollers eingebunden werden.
Nachteile, die man bei diesem Testaufbau akzeptiert hat, sind unter anderem:
- Gewisse Fehler können nicht gefunden werden.
Zum Beispiel aufgrund von verschiedenen Timings auf Test-Host und Mikrocontroller. Die meisten kritischen Timings laufen auf dem Radio-SoC, daher ist dieser Punkt unkritisch. Systemtests sind als Ergänzung notwendig. - Die Radio-Verbindung wird nur im (unrealistischen) störungsfreien Fall getestet. Tests bei denen gezielt Störungen eingespeisten werden, sind weiterhin notwendig.
Fazit
Der Aufwand für das Aufsetzten und die Wartung solcher Tests darf nicht unterschätzt werden. Starten Sie mit einem simplen Testaufbau und setzen Sie den Fokus auf Stabilität, Benutzbarkeit und auf die wichtigen Teile der Software, die sich nicht durch Unit-Tests prüfen lassen und aufwändig sind manuell zu testen.
Eine gute Grundlage ist entscheidend, um den Aufwand für die Automatisierung weiterer Teile der Soft- oder Hardware zuverlässig einschätzen zu können.
Und schlussendlich: Setzen Sie die automatisierten Tests in allen Phasen des Projekts ein.
Hoffentlich konnte Ihnen dieser Artikel hilfreiche Denkanstösse vermitteln, um ein solches Projekt erfolgreich und befriedigend umsetzen zu können. Viel Erfolg!
Haben Sie Fragen? Gerne beraten wir Sie konkret bei Ihrem Projekt, führen Workshops durch oder realisieren für Sie ein Testframework.
Wir freuen uns auf Ihre Kontaktaufnahme.

Nicola Jaggi
BSc BFH in Elektro- und Kommunikationstechnik
Embedded Software Engineer
Über den Autor
Nicola Jaggi arbeitet seit 11 Jahren als Embedded Software Engineer bei der CSA Engineering AG. Sein Fokus liegt auf der Entwicklung von Firmware in C++ auf STM32.
In vergangen Jahren hat er ausserdem mehrere Testautomatisierungen aufgesetzt, erweitert und verwendet.