Dynamische Analyse für Embedded Systeme
Embedded-Code-Coverage ohne Instrumentierung messen: Warum Hardware-Tracing im Systemtest die Beobachtbarkeit löst, die Unit-Tests allein nicht liefern können.

Embedded Testing bezeichnet das Testen von Software auf realer Hardware unter Echtzeit-Bedingungen, weil Simulationen die physikalischen und zeitlichen Eigenschaften eingebetteter Systeme nicht vollständig abbilden können. Der Goldstandard dafür ist Embedded Trace: eine Hardware-Schnittstelle im Mikrocontroller, die den Kontrollfluss nach außen sendet, ohne die Applikation zu beeinflussen, und so erstmals Code-Coverage-Messung direkt im Integrationstest ermöglicht.
Das Wichtigste in Kürze
- Embedded Trace liest den Kontrollfluss eines Mikrocontrollers über dedizierte Hardware-Schnittstellen aus, ohne die Ausführungszeit der Applikation zu verändern, was klassische Instrumentierung grundsätzlich nicht leisten kann.
- Code-Coverage-Messung im Integrationstest auf echter Hardware ist technisch jetzt möglich und löst das zentrale Problem, dass bisher nur Unit-Tests auf dem PC oder auf dem Target isoliert gemessen werden konnten.
- Instrumentierter Code bläht den Speicherbedarf so stark auf, dass Safety-kritische Embedded-Systeme schlicht keinen Platz mehr dafür haben, weil im Schnitt jede fünfte Instruktion eine Entscheidung ist, hinter der ein Counter stehen muss.
- Embedded-Tester brauchen zwingend sowohl Elektrotechnik- als auch Informatik-Kenntnisse, weil ein Bit nicht gesetzt wird, wenn der Stromkreis dahinter nicht korrekt geschlossen oder geöffnet ist.
- Sicherheitsnormen wie DO-178C erlauben bereits heute Coverage-Nachweise durch Integrationstests, werden aber in der Praxis noch überwiegend auf Unit-Ebene erfüllt, obwohl das teurer und weniger aussagekräftig ist.
Was Embedded Testing schwieriger macht als Tests für Web-Anwendungen
Embedded Testing unterscheidet sich von klassischem Softwaretest vor allem durch Ressourcenknappheit, Echtzeitverhalten und die enge Verzahnung mit der Elektronik. Wer Embedded-Systeme testet, kommt um Grundlagen der Elektrotechnik nicht herum.
Der Speicher ist klein, der Platz begrenzt, die Zeitanforderungen sind streng. Ein Bit wird im Speicher nur dann gesetzt, wenn auch der Stromkreis dahinter stimmt. Wer einen Schaltplan nicht lesen kann und das ohmsche Gesetz nicht kennt, kann auf dieser Ebene nicht sinnvoll testen.
Dazu kommt das Profil der Anwendung. Ein Embedded-System arbeitet in Echtzeit. Lässt man dieses Echtzeitverhalten beim Testen außer Acht, prüft man unter Umständen nicht das System, das später tatsächlich läuft.
Das Berufsbild spiegelt diese Anforderung. Viele Embedded-Entwickler kommen aus der Elektrotechnik, nicht aus der reinen Informatik. Martin Heininger hat selbst Elektrotechnik studiert. Beide Welten müssen zusammenkommen, und genau das wollen muss man als Voraussetzung mitbringen.
Warum die Hardware die Wahrheit ist
Im sicherheitskritischen Embedded-Bereich gilt: Die Hardware ist die einzig belastbare Testumgebung. Eine Simulation reicht für die Abnahme nicht aus, weil sich ihre Korrektheit kaum beweisen lässt.
Auf dem PC lässt sich durchaus testen, vor allem auf Unit-Ebene und unter bestimmten Bedingungen. Je weiter man jedoch Richtung System- und Abnahmetest kommt, desto stärker führt kein Weg an der realen Elektronik vorbei.
Der Grund liegt in der Frage, die jeder Sicherheitsnachweis aufwirft: Kannst du beweisen, dass die Simulation die Wahrheit abbildet? In der Praxis kann man das selten. Also testet man am physischen System.
Die Hardware-Realität ist zudem komplexer geworden. Früher gab es eine CPU mit externem Speicher, klare Modelle und vorhersagbare Laufzeiten. Eine Software brauchte eine bestimmte Anzahl CPU-Takte und war zu einem definierten Zeitpunkt fertig.
Bei heutigen Multicore-Systemen mit Caches verdrängen sich Abläufe gegenseitig aus dem Speicher. Der Determinismus ist weg oder nur mit hohem Aufwand wiederherzustellen. Für viele moderne SoC-Systeme existieren keine genauen Modelle mehr. Was bleibt, ist Ausprobieren am echten System, kombiniert mit der Fähigkeit, hineinzuschauen.
Wo sich Embedded Testing vom IT-Test unterscheidet
Drei Bereiche trennen Embedded-Tests deutlich vom klassischen IT-Test: Volumentests, Code-Coverage-Anforderungen und Beobachtbarkeit.
Den Volumentest mit riesigen Datenbanken und realen Personendaten gibt es im Embedded-Bereich so nicht. Was dort als Lasttest gilt, ist eher ein Stresstest auf einem Bus, etwa CAN oder Ethernet, mit vergleichsweise wenig Daten. Für einen IT-Tester wären diese Datenmengen kaum der Rede wert.
Bei der Code-Coverage drehen sich die Verhältnisse um. Im IT-Umfeld sind 100 Prozent Coverage, jede Zeile oder gar jede Bedingung, weder üblich noch bei der schieren Größe sinnvoll. Im Sicherheitsumfeld gilt das Gegenteil: Steckt dort ein Fehler im Code, entsteht ein echtes Problem. Also muss alles getestet werden.
Auch die Security folgt einem anderen Muster. Hier hat die IT einen Vorsprung, weil sie länger Erfahrung mit entsprechenden Tests und Schutzkonzepten hat. Im Embedded-Bereich fängt das Thema gerade erst an. Eine verbreitete Strategie lautet: Gibt es eine Schnittstelle nach außen, muss das größere System auf der anderen Seite das kleine Embedded-System schützen.
Warum Instrumentierung beim Integrationstest an Grenzen stößt
Instrumentierung funktioniert hervorragend für isolierte Unit-Tests, wird aber bei System- und Integrationstests zum Problem. Sie verändert das System, das man eigentlich prüfen will.
Der Mechanismus: Etwa jede fünfte Instruktion ist eine Entscheidung, die mitprotokolliert werden muss. Hinter jeder Entscheidung steht ein Zähler, der bei jedem Durchlauf gelesen, erhöht und zurückgeschrieben wird. Das bläht den Code stark auf.
Daraus folgen zwei unangenehme Effekte. Erstens passt der instrumentierte Code oft nicht mehr in den begrenzten Speicher. Zweitens verändert sich die Ausführungszeit. Ein Read-Modify-Write im Cache geht schnell, im externen Speicher dauert er schnell den Faktor 100 länger.
Bei einem System mit garantierten Antwortzeiten oder Reaktionen auf Interrupts kippt damit das Verhalten. Man testet am Ende das instrumentierte System, das mit der eigentlichen Anwendung nur noch bedingt zu tun hat.
In der Luftfahrt ist diese Frage so kritisch, dass die Instrumentierung teils im Release-System verbleibt, damit man genau den getesteten Code ausliefert. Andere Bereiche testen einmal mit und einmal ohne Instrumentierung und hoffen, dass beide Varianten sich gleich verhalten.
Embedded Trace: Beobachten, ohne das System zu stören
Embedded Trace liefert Einblick in das laufende System, ohne dass die Anwendung etwas davon merkt. Eine Hardware-Einheit an der CPU funkt nach außen, was die CPU tut, ganz ohne die Anwendung zu verändern.
Diese rückwirkungsfreie Beobachtung umgeht die zentralen Probleme der Instrumentierung. Kein aufgeblähter Code, keine verfälschte Laufzeit. Alexander Weiss bezeichnet das als Goldstandard der Beobachtung, allerdings mit klaren Voraussetzungen.
An der CPU ist eine Hardware, die nach außen funkt, was die CPU macht, ohne dass die Applikation das mitbekommt.
Alexander Weiss
Die wichtigste Voraussetzung ist physischer Natur: Die Trace-Schnittstelle sitzt zwar auf fast jedem modernen Mikrocontroller, muss auf der Platine aber auch zugänglich sein. In frühen Hardware-Versionen werden die Trace-Punkte oft an verschiedenen Stellen der Platine zusammengesucht, bis in späteren Redesigns der passende Stecker vorhanden ist.
Der praktische Rat daraus: Schreib früh ins Lastenheft, dass die Trace-Stelle vorgesehen werden muss. Sie wird nicht für den Produktivbetrieb gebraucht, sondern fürs Debuggen und Testen, und genau dort fehlt sie sonst.
Wie Trace-Daten ausgewertet werden
Trace-Daten lassen sich nicht in Software in Echtzeit auswerten, sondern brauchen dedizierte Hardware. Selbst der schnellste Mikrocontroller produziert Datenmengen, die ein reiner Software-Decoder nicht live mitrechnen könnte.
Für den Transport gibt es mehrere relevante Protokolle. Parallele Ausgabe über viele Pins ist möglich, aber unschön wegen des Pin-Bedarfs bei Bandbreiten im Gigabit-Bereich. High-Speed-serielle Schnittstellen wie Aurora geben über eine Lane mehrere Gigabit aus, optional über mehrere Lanes.
Eine dritte Variante nutzt eine Systemschnittstelle wie PCI Express. Das ist elegant und breit verfügbar, aber leicht intrusiv: Sobald sich die Trace-Einheit Bandbreite auf dem PCI Express greift, entsteht wieder eine Rückwirkung. Eine dedizierte serielle Trace-Schnittstelle bleibt technisch die sauberste Lösung, ist aber nicht immer vorhanden.
Die Auswertung übernimmt ein FPGA, ein frei programmierbarer Großchip. Er nimmt die einzelnen Trace-Schnipsel massiv parallel auf und rechnet das Protokoll aus. Für Code Coverage steht dort pro Instruktionsadresse ein eigener Hardware-Counter. Nach der Messung ergibt die Summe über alle Counter, wie oft welche Stelle des Kontrollflusses durchlaufen wurde.
Das Trace-Protokoll ist stark komprimiert. Ausgegeben wird nicht der konkrete Adresssprung, sondern nur, ob ein direkter Sprung genommen wurde oder nicht. Ohne das Binary der Anwendung ist dieser Datenstrom nicht interpretierbar, was nebenbei die Security-Bedenken entschärft. Wer das Trace-Interface zusätzlich absichern will, kann es per Fuse dauerhaft sperren.
Code Coverage im Integrationstest statt im Unit-Test
Embedded Trace ermöglicht, was lange nicht ging: Code-Coverage auf dem realen Target im System- und Integrationstest zu messen. Bisher war Coverage durch die Instrumentierung praktisch auf den Unit-Test beschränkt.
Die ursprüngliche Idee hinter der Coverage-Messung stammt aus der Luftfahrt um 1992. Requirements und Tests teilen eine Schwäche: Man weiß nie genau, wann sie vollständig sind. Code-Coverage dagegen ist Mathematik auf Basis des Quellcodes, bei 100 Prozent ist die Aussage eindeutig.
Gedacht war Coverage als Werkzeug, um fehlende Requirements und fehlende Tests aufzuspüren, indem man die Abdeckung gegen beide stellt. Auf Unit-Ebene scheiterte das jedoch, weil dort die Requirements fehlen. Genau diese Lücke schließt die Messung im Integrationstest.
Auf dieser Ebene lässt sich grundsätzlich sogar während eines realen Betriebs messen, theoretisch in einem Testflug, praktisch im Labor am Einzelsteuergerät. Die Hardware liefert die Wahrheit, und der durchlaufene Code wird sichtbar.
Den Nutzen sieht Martin vor allem in der Funktional-Sicherheit. Das formalisierte Unit-Testen in der Safety ist heute mit großen Test-Teams sehr teuer und liefert oft wenig Mehrwert.
Integrationstest vor Unit-Test, mit Begründungspflicht
Sinnvoll wäre, Integrationstests die Priorität zu geben und Unit-Tests nur dort ergänzend einzusetzen, wo sich Coverage anders nicht erreichen lässt. Die Begründung sollte vor dem zusätzlichen Unit-Test stehen, nicht danach.
Luftfahrtnormen wie die DO-178C lassen heute beide Wege offen. Du darfst die geforderte Coverage über Integrationstests oder über Unit-Tests erbringen. Diese Freiheit entstand auch in Kenntnis der damaligen technischen Möglichkeiten.
Wichtig ist die Abgrenzung: Das ist kein Plädoyer gegen Unit-Tests und keine Rückkehr zur Big-Bang-Integration. Alles, was ein Entwickler sinnvollerweise an Unit-Tests macht, soll bestehen bleiben und gehört zurück in die Hand des Entwicklers. Kritisiert wird der überzogene Formalismus, der in der Safety viel Geld bindet.
Normen bilden immer den Stand der Technik zum Zeitpunkt ihrer Entstehung ab. Im Softwarebereich entwickelt sich vieles schnell, weshalb eine Norm bei Erscheinen bereits hinterherhinken kann. Damit eine Technologie wie Embedded Trace ihre Chance bekommt, müssen Normen Raum für neue Verfahren lassen.
Ähnliche Beiträge

Richard Seidl
•2. Juni 2026
Patient Agilität: Liegt agiles Arbeiten im Sterben?

Richard Seidl
•26. Mai 2026