Bild 1: Die harmonisierte Medizingeräte-Norm IEC 62304 fordert mehrere Testebenen, die mit verschiedenen Abstraktionsebenen der Entwicklung korrespondieren.

Bild 1: Die harmonisierte Medizingeräte-Norm IEC 62304 fordert mehrere Testebenen, die mit verschiedenen Abstraktionsebenen der Entwicklung korrespondieren.Hölzer-Klüpfel

Der Software-Qualität kommt bei komplexen Medizingeräten eine entscheidende Bedeutung zu. Wenn Blutzuckermessgeräte bei besonders hohen Werten abstürzen oder Bildarchive beim Update Röntgenbilder verlieren, dann sind Patienten und Anwender schnell in Gefahr. Um sich als Hersteller von Medizinprodukten vor Softwarefehlern zu schützen, muss man in allen Schritten der Entwicklung sorgfältig arbeiten. Die harmonisierte Norm IEC 62304 beschreibt die Mindestanforderungen an den Entwicklungsprozess und die Tests. Die Norm fordert mehrere Testebenen (Bild 1):

  • Die Software-Systemprüfung weist nach, dass das Produkt alle Softwareanforderungen erfüllt.
  • Der Software-Integrationstest überprüft das Zusammenspiel der Softwarekomponenten untereinander.
  • Die Verifikation der Softwareeinheiten stellt die Einhaltung des Softwaredesigns sicher. Hier ist zwar nicht explizit ein Test verlangt, in der Praxis wird dazu jedoch in der Regel von Unit-Tests Gebrauch gemacht.

Um einen Test effektiv durchzuführen, sind eine ganze Reihe von Aktivitäten nötig:

  • Tests planen und spezifizieren: Dabei ist festzulegen, wie die durchzuführenden Testschritte aussehen, welche Ergebnisse bei der Ausführung des Tests erwartet werden, und wann ein Test als bestanden oder gescheitert gilt.
  • Tests ausführen: Dabei werden die Testschritte durchgeführt und die Ergebnisse aufgezeichnet.
  • Tests auswerten: Dabei werden die Ergebnisse begutachtet um festzustellen, welche Tests bestanden wurden.
  • Alle diese Aktivitäten dokumentieren.

Betrachtet man den Aufwand von Softwaretests, dann springen zwei Probleme ins Auge: Zum einen fallen die wesentlichen Aufwände gegen Ende eines Entwicklungsprojektes an. Zum anderen müssen bei der Korrektur von erkannten Fehlern unter Umständen große Teile des Softwaretests erneut ablaufen. Wenn ein Entwicklungsprojekt iterativ arbeitet, also von vorneherein mit einer Reihe von Zwischenversionen plant, dann sind auch die Testphasen mehrfach zu durchlaufen. Eine manuelle Testausführung, bei der Menschen alle Schritte der Testspezifikation ausführen, aufzeichnen und auswerten, ist dann kaum noch effizient. Hier lohnen sich automatisierte Tests.

Automatisierter Softwaretest

Am einfachsten ist eine Testautomatisierung noch beim Unit-Test zu erreichen. Er prüft die kleinsten Einheiten der Software, also beispielsweise Funktionen oder Klassen, daher lassen sich oft auch die Testroutinen in der gleichen Programmiersprache implementieren. Dabei helfen Test-Frameworks wie Cpp-Unit oder Testwerkzeuge wie Cantata oder Vectorcast. Da der Unit-Test einzelne Software-Einheiten prüft, gibt es bei der Gestaltung der Test viele Freiheiten: nicht zu testende Software-Einheiten lassen sich durch Stubs oder Mocks ersetzen, die unter der Kontrolle des Testtools stehen. So lassen sich auch schwierige Fehlersituationen, beispielsweise Speicherengpässe, sicher simulieren und die Reaktion des Testobjekts überprüfen.

Auf einen Blick

Software-Systemtest: Das klingt wie eine weitere Spielart von Unit- und Integrationstest, bezieht sich aber tatsächlich auf die komplette Software in einem vollständigen System. Hier scheitern reine Software-Frameworks, ein HiL-Teststand ist gefragt. Den kann man mit handelsüblichen Eval-Boards auch selbst aufbauen und damit moderne Entwicklungsprozesse unterstützen.

Der Software-Integrationstest lässt sich mit den gleichen Werkzeugen automatisieren wie der Unit-Test. Der Unterschied liegt in der Sichtweise beim Erstellen der Testfälle: Der Unit-Test ist ein White-Box-Test, bei dem man die Kenntnis von der inneren Struktur (also vom Quellcode) der zu testenden Einheiten nutzt. Beim Integrationstest dagegen betrachtet man nur die (hoffentlich ausreichend dokumentierte) Schnittstelle der Komponenten und testet gegen diese Schnittstelle, ohne auf Details der Implementierung zuzugreifen. Aber der Test kann immer noch durch programmierte Testroutinen erfolgen.

Beim Software-Systemtest ist die Automatisierung nicht mehr so einfach. Sein Ziel muss sein, das möglichst unmodifizierte Software-System auf der Zielhardware gegen seine Anforderungen zu testen. Diese Tests zu automatisieren ist schwierig, weil das Software-System in der Form, in der es in ein Medizinprodukt eingebaut wird, oft keine Schnittstellen mehr hat, über die Test- und Fehlerzustände hervorgerufen werden können. Die Tests müssen daher auf die vorhandenen (in der Regel elektronischen) Schnittstellen der Zielhardware zugreifen. Man spricht daher auch von einem Hardware-in-the-Loop-Test (HiL-Test). Die folgenden Abschnitte beschreiben ein Beispiel für einen solchen HiL-Test, der ein Steuergerät für ein medizinisches Therapiegerät komplett automatisiert prüft.

Automatisierter Software-Systemtest

Therapiegeräte wie Beatmungsmaschinen, Dialysegeräte oder Infusionsgeräte weisen oft eine typische Systemarchitektur auf, wie sie in Bild 2 skizziert wird.

Bild 2: Die Systemarchitektur typischer Medizingeräte arbeitet mit einem Supervisor, der die Software-Abläufe im Controller überwacht.

Bild 2: Die Systemarchitektur typischer Medizingeräte arbeitet mit einem Supervisor, der die Software-Abläufe im Controller überwacht.Hölzer-Klüpfel

Die Interaktion mit dem Benutzer erfolgt über einen dedizierten Rechner oder Prozessor, der beispielsweise einen Touchscreen ansteuert. Die eigentliche Steuerung der Therapie übernimmt ein Steuergerät, das in der Abbildung als „Controller“ bezeichnet ist. Dieser Controller hat viele Schnittstellen zur Hardware, also zu den Sensoren und Aktuatoren, mit denen die Behandlung kontrolliert wird. Aus Gründen der funktionalen Sicherheit gibt es zudem oft noch einen unabhängigen Kanal, der hier „Supervisor“ heißt. Er stellt sicher, dass der Patient durch das Gerät auch dann nicht gefährdet wird, wenn ein Software- oder Hardware-Fehler im Controller oder dem User-Interface vorliegen sollte. Typische Aufgabe des Supervisors sind Grenzwerte der Therapieparameter überwachen und Gefahrensituationen erkennen und darauf beispielsweise mit Alarmen reagieren. Der Supervisor greift ebenfalls auf Sensoren und Aktuatoren der Hardware zu, wenn auch unter Umständen auf andere, redundant ausgelegte.

Dialysegerät als Beispiel

Im Beispielsystem – einem Dialysegerät – befindet sich der Großteil der zu testenden Software im Controller und im Supervisor, und diese beiden Prozessoren befinden sich auf einer gemeinsamen Platine. Um den Test beider Knoten zu automatisieren, ist ein Testsystem gefordert, das die elektrischen Schnittstellen der Platine simuliert beziehungsweise überwacht. Eine genauere Analyse der Hardware im Beispielprojekt ergab, dass dazu die folgenden Schnittstellen (insgesamt etwa 150 Signale) zu bedienen sind:

  • Eine ganze Reihe digitaler I/O-Schnittstellen
  • Mehrere serielle RS-232-Schnittstellen
  • I2C-Schnittstellen, vor allem zu Sensoren
  • PWM-Signale zur Steuerung von Aktoren
  • Einige wenige analoge Ein- und Ausgabesignale

Ein gängiger Ansatz, um diese Schnittstellen für einen HiL-Test zu simulieren wäre es nun, zu einem Katalog zu greifen, entsprechend viele Standard-IO-Karten einzukaufen und daraus ein Testsystem aufzubauen. Bei Standard-Karten ließe sich dann auch eine Standard-Software verwenden, um die Tests zu automatisieren.

Eigens entwickelter Teststand

Im Beispielprojekt wurde dieser Weg nicht beschritten, und zwar aus vier Hauptgründen:

  • Um Testdurchlaufzeiten von wenigen Tagen zu erreichen, sollten mehrere Teststände aufgebaut werden. Die Kosten für die Standard-IO-Karten wären daher kräftig ins Gewicht gefallen.
  • Viele der Signale müssen nur mit einer sehr geringen Zeitauflösung behandelt werden, daher war gar keine leistungsfähige Simulationshardware nötig.
  • Einige wenige Signale dagegen müssen mit sehr hoher Zeitauflösung bedient werden, sodass Standard-Hardware nicht geeignet erschien.
  • Viele Probleme beim Aufbau von Testsystemen entstehen in der Verkabelung, sodass auf jeden Fall eine Leiterplatte für die Verschaltung entwickelt werden sollte.

Das Hauptargument gegen eine Standardlösung war aber der Aufwand, passende Testskripte zu entwickeln. Um etwa 600 Testskripte zeitgleich mit der Produktsoftware zu entwickeln, war es das Ziel, die Semantik der Testskript auf die gleiche Abstraktionshöhe wie die Software-Anforderungen zu heben. Dadurch verkürzen sich sowohl die Zeit für die Entwicklung der Skripte als auch die Zeit für das Review gegen die Anforderungen. Und das schien nur mit einer Eigenentwicklung des Testsystems in kurzer Zeit machbar.

Testsystem

Um ein Testsystem zügig entwickeln zu können, und um die Kosten in einem vernünftigen Rahmen zu halten, bot es sich an, das Testsystem aus Standardkomponenten aufzubauen. Im Beispiel hier wurden dazu etwa fertige Eval-Boards für FTDI-4232-Chips verwendet, die wahlweise 32 Digital-IOs, vier serielle Schnittstellen oder I2C-Ports simulieren. Das genügt zum Simulieren und Messen aller Signale, bei denen es nicht auf extreme Zeitauflösung ankommt. Für die verbleibenden Schnittstellen mit besonderen Anforderungen kam ein Eval-Board für einen STM32-Mikroprozessor zum Einsatz. Alle diese Komponenten wurden per USB an einen PC angebunden, der die Testskripte ausführt (Bild 3).

Bild 3: Im Blockschaltbild der Automatisierungslösung ist zu erkennen, dass es in bester HiL-Tradition alle Ein- und Ausgabemöglichkeiten des geprüften Systems steuert und überwacht.

Bild 3: Im Blockschaltbild der Automatisierungslösung ist zu erkennen, dass es in bester HiL-Tradition alle Ein- und Ausgabemöglichkeiten des geprüften Systems steuert und überwacht.Hölzer-Klüpfel

In diesem speziellen Fall wurde die Platine mit dem zu testenden System direkt auf dem Teststand montiert und mit direkter 1:1-Verkabelung angebunden. Dadurch haben sich die Probleme mit der Verkabelung deutlich reduziert und das System läuft sehr stabil.

Um automatisch mehrere Testläufe hintereinander durchzuführen, war es notwendig, die Spannungsversorgung des zu testenden Systems zu kontrollieren, es also automatisch ein- und ausschalten zu können. Dabei wurde schnell deutlich, dass Probleme auftreten, wenn die Spannungsversorgung zum zu testenden System unterbrochen ist, der Teststand allerdings Spannung führt – in dem Fall werden Teile der zu testenden Schaltung mit Spannung versorgt und können Schaden nehmen. Daher wurden alle Verbindungen über Tri-State-Transceiver isoliert. Die Software des Mikrocontrollers stellt zudem sicher, dass die Isolierung erst aufgehoben wird, wenn die Spannungsversorgung aktiv ist.

Testsoftware

Die Software, mit welcher die Tests automatisch durchgeführt werden, bestand aus mehreren Teilen:

  • Embedded-Software für den im Teststand integrierten Mikrocontroller.
  • PC-Applikation, welche die Testskripte ausführt und die Ergebnisse der Tests bewertet und dokumentiert.
  • Die eigentlichen Testskripte.

Um das Ziel zu erreichen, das Abstraktionsniveau der Testskripte in etwa dem der Software-Anforderungen anzupassen, wurde nach Analyse der Anforderungen eine spezielle, einfache XML-Sprache definiert. Diese kommt mit erstaunlich wenigen Kommandos aus:

  • „set“: Ändert eine simulierte Größe.
  • „wait“: Erwartet den Eintritt eines beobachteten Zustands.
  • „send“: Schickt eine serielle Nachricht.
  • „expect“: Erwartet die Ankunft einer seriellen Nachricht.
  • „monitor“: Überwacht den Systemzustand nebenläufig.
  • „delay“: Wartet ab.
  • „repeat“: Wiederholt Anweisungen für eine Anzahl oder eine Zeit.
  • „verify“: Zeigt einen Trace zu einer Anforderung.
Bild 4: Die Test-Cases lassen sich mit recht einfachen XML-Dateien formulieren.

Bild 4: Die Test-Cases lassen sich mit recht einfachen XML-Dateien formulieren.Hölzer-Klüpfel

Trotz der wenigen Kommandos lassen sich damit sehr mächtige Testskripte definieren. Das Beispiel in Bild 4 zeigt einen Testfall für eine sehr einfache Anforderung, nämlich den Selbsttest der Alarm-LED. Das entsprechende Requirement „REQ1234: Test der Alarm-LED“ fordert: „Nach dem Power-on-Self-Test blinkt die Alarm-LED fünfmal mit 1 Hz und 50 % Einschaltdauer.“ Bild 4 zeigt das zugehörige Testskript.

Lange Testläufe

Das Vorgehen bei einem automatisierten Software-Systemtest unterscheidet sich deutlich von Unit- oder Integrationstests, vor allem weil hier die unveränderte Systemsoftware getestet wird. Daher glaubt die Software, eine ganz normale Therapie durchzuführen. Im Beispiel ist das eine Dialyse-Behandlung, und die dauert gerne einmal vier Stunden. Genau so viel Zeit benötigt daher auch ein kompletter Durchlauf einer problemlosen Testsituation.

Diesem problemlosen Durchlauf, häufig auch als Schönwetter- oder Greenlight-Szenario bezeichnet, kommt eine wesentliche Bedeutung zu. Zum einen muss er nachweisen, dass eine vollständige Behandlung korrekt ausgeführt werden kann. Zum anderen ist er die Grundlage fast aller anderen Tests, die Schlechtwetter- oder Redlight-Tests. Um zum Beispiel die Reaktion der Supervisor-Software auf die Fehlfunktion eines Sensors zu überprüfen, führt man das Greenlight-Szenario bis zu der Stelle aus, an der man das Fehlverhalten simulieren möchte. Dann wird der Teststand den Fehler nachstellen und die Reaktion überprüfen. Eventuell befindet sich das System dann in einem Fehlerzustand, und für den nächsten Test muss man von vorne beginnen.

Zwei Wochen an einem Wochenende

Im angesprochenen Beispielprojekt gab es am Ende zwei Schönwetter-Tests (für unterschiedliche Therapieoptionen) mit einer Laufzeit von je vier Stunden, und mehrere hundert Schlechtwetter-Tests, mit einer Gesamtlaufzeit von ungefähr 14 Tagen. Durch die Verteilung auf sechs Teststände ergab sich daraus eine Durchlaufzeit für einen kompletten Software-Systemtest von 2,5 Tagen – idealerweise über ein Wochenende. Vergleicht man das mit den zuvor für die manuelle Testdurchführung geschätzten Zeiten von drei Monaten bei sechs Testern, dann wird offenkundig, dass die Automatisierung des Software-Systemtests nicht nur Kosten spart. Sie ist geradezu unabdingbar für agile Softwareentwicklung mit Sprint-Zyklen von zwei Wochen.