Bitcrush Spezialist für Embedded-Software-Tests und Qualitätsprozesse https://bitcrushtesting.com/ Bitcrush https://bitcrushtesting.com/ https://bitcrushtesting.com/image/brand/icon-1-1.png https://bitcrushtesting.com/image/brand/icon-2-1.png 2025-09-28T20:05:27Z Yocto erstelltes Image in QEMU testen Bernhard Trinnes https://bitcrushtesting.com/ https://bitcrushtesting.com/blog/run-yocto-image-in-qemu/ 2025-09-25T19:00:00Z 2025-09-25T19:00:00Z Mit QEMU lässt sich ein Embedded-Linux-System direkt auf dem Host-PC starten, ohne sofort reale Hardware einsetzen zu müssen. Zur Demonstration verwenden wir Poky, das Referenz-Buildsystem des Yocto-Projekts. Es ist kompakt, flexibel erweiterbar und bietet alle Werkzeuge, die für den Einstieg in das Erstellen, Ausführen und Testen von Linux-Images notwendig sind.

Die hier gezeigten Schritte lassen sich nicht nur für Poky anwenden, sondern auch auf eigene Images übertragen – etwa für SoC-Plattformen wie i.MX. Der Ablauf zum Bauen, Booten und Testen bleibt im Wesentlichen gleich, lediglich die Zielmaschine und zusätzliche Layers unterscheiden sich.

Durch diese Eigenschaften eignet sich Poky besonders gut, um erste Erfahrungen mit Emulatoren zu sammeln und automatisierte Tests in den Entwicklungsprozess einzubinden. Dieser Artikel zeigt den gesamten Ablauf: vom Herunterladen der Quellen über den Image-Build bis hin zum Start in QEMU und der Ausführung von Tests.

Voraussetzungen

  • Linux-Hostsystem (z. B. Ubuntu oder Fedora)
  • git, tar und Standard-Build-Tools (gcc, make, python3, etc.)
  • Mindestens 50 GB freier Speicherplatz

Schritt 1: Poky-Repository klonen

git clone git://git.yoctoproject.org/poky
cd poky

Optional: einen stabilen Branch verwenden, z.B. scarthgap:

git checkout scarthgap

Schritt 2: Build-Umgebung initialisieren

source oe-init-build-env

Dadurch wird das Verzeichnis build/ angelegt. In conf/local.conf lassen sich Einstellungen anpassen, etwa die Anzahl paralleler Jobs:

BB_NUMBER_THREADS = "8"
PARALLEL_MAKE = "-j 8"

Schritt 3: Image bauen

Ein minimales Image:

bitbake core-image-minimal

Der Build-Prozess dauert je nach Hardware bis zu mehreren Stunden. Das Ergebnis liegt in:

build/tmp/deploy/images/qemux86-64/

Schritt 4: Image in QEMU starten

Poky bringt ein Startskript mit:

runqemu qemux86-64

Damit wird ein virtuelles System auf Basis von QEMU hochgefahren. Es erscheint eine Login-Shell (Standard-Benutzer: root, kein Passwort).

Schritt 5: Tests ausführen

Das Yocto-Projekt unterstützt die Testinfrastruktur (oeqa). Beispiel: einfache Sanity-Tests.

Für eigene Tests lassen sich Python-Tests in meta/lib/oeqa/runtime/ ergänzen. Ein Beispiel für einen Ping-Test:

from oeqa.runtime.case import OERuntimeTestCase
from oeqa.core.decorator.oetimeout import OETimeout

class PingTest(OERuntimeTestCase):
    @OETimeout(60)
    def test_ping(self):
        status, output = self.target.run("ping -c 3 8.8.8.8")
        self.assertEqual(status, 0, msg="Ping fehlgeschlagen:\n%s" % output)

Schritt 6: Fehleranalyse

Falls Tests fehlschlagen:

  • build/tmp/log/oeqa/ prüfen
  • QEMU mit runqemu interaktiv starten
  • Log-Dateien in build/tmp/work/.../temp/log.do_* analysieren

Fazit

QEMU bietet eine flexible Möglichkeit, Embedded-Linux-Images schnell und unabhängig von echter Hardware zu starten. Entwickler können damit Bootprozesse nachvollziehen, Funktionen prüfen und automatisierte Tests ausführen. Poky dient hier nur als Beispiel zur Image-Erstellung, der Ablauf lässt sich aber ebenso auf eigene oder boardspezifische Builds – etwa für i.MX – übertragen.

Damit wird QEMU zu einem wichtigen Werkzeug in der Embedded-Entwicklung: für frühes Prototyping, kontinuierliche Tests und stabile Release-Prozesse.

]]>
Softwareanforderungen für sicherheitskritische Anwendungen Bernhard Trinnes https://bitcrushtesting.com/ https://bitcrushtesting.com/blog/software-requirements-for-safety-applications/ 2025-09-12T19:00:00Z 2025-09-12T19:00:00Z Bei der Entwicklung sicherheitskritischer Systeme sind Softwareanforderungen nicht nur ein Punkt auf einer Checkliste – sie bilden das Fundament für alles Folgende. Vom Design und der Verifikation über die Zertifizierung bis hin zur Wartung: Die Klarheit und Korrektheit Ihrer Anforderungen kann über Erfolg oder Scheitern Ihres Produkts entscheiden, insbesondere dann, wenn Leben vom Verhalten des Systems abhängen.

Egal ob Sie eine Insulinpumpe oder einen Druckregler für ein Kernkraftwerk entwickeln: Das Schreiben von Softwareanforderungen für sicherheitskritische Anwendungen erfordert eine disziplinierte Vorgehensweise. Dieser Artikel zeigt, wie man präzise, eindeutige und überprüfbare Anforderungen formuliert, die Industriestandards erfüllen und die Zertifizierung unterstützen.

Hochwertige Anforderungen schreiben

Die meisten Anforderungen werden noch in natürlicher Sprache (NL) formuliert. NL ist flexibel und leicht verständlich, aber anfällig für Mehrdeutigkeit. Schon eine Formulierung wie „bei Bedarf“ kann mehrere Interpretationen zulassen – und damit kritische Fehler verursachen. Deshalb braucht sicherheitsrelevante Entwicklung auch in NL Regeln und Struktur. Eine gute Softwareanforderung ist:

  • korrekt und klar
  • konsistent und widerspruchsfrei
  • testbar und verifizierbar – sie muss messbare Kriterien definieren
  • frei von Konjunktionen und Ausnahmen
  • rollenspezifisch – benennt den Benutzertyp

Beispielstruktur:

Der Bediener soll in der Lage sein, [Aktion] am [Objekt] durchzuführen, um [gewünschten Zustand] zu erreichen.

Jede Anforderung sollte definieren:

  • Wer die Aktion durchführt (Benutzerrolle)
  • Was getan wird (Aufgabe und Objekt)
  • Warum bzw. welches Ergebnis erwartet wird
  • Wer das Ergebnis erhält oder verwendet

Stil und Struktur

Eine gut formulierte Anforderung folgt typischerweise einem Subjekt–Prädikat–Objekt (S-P-O)-Muster:

Subjekt Prädikat Objekt
Das System soll anzeigen die aktuelle Herzfrequenz.

ISO/IEC/IEEE 29148:2018 beschreibt, wie man klare und testbare Anforderungen schreibt und standardisiert die Verwendung modaler Verben:

  • Shall (soll): Kennzeichnet eine verpflichtende Anforderung.
  • Will (wird): Beschreibt eine Tatsache oder Absicht, keine Anforderung.
  • Should (sollte): Empfohlene Anforderung; nicht verpflichtend, Abweichungen müssen aber begründet werden.
  • Must (muss): Wird manchmal für Naturgesetze oder unvermeidbare Folgen verwendet, sollte jedoch nicht anstelle von „shall“ für Anforderungen genutzt werden.

Best Practice: Verwenden Sie „shall“ nur einmal pro Anforderung. Vermeiden Sie zusammengesetzte Anforderungen ohne „und“, „oder“ oder „mit“. Das Kombinieren von Aktionen macht die Anforderung untestbar und erzeugt mehrere Anforderungen in einer. Wörter wie „ist“, „sind“, „war“ oder „muss“ sind für beschreibende oder einleitende Abschnitte geeignet.

Jede Anforderung sollte beschreiben, was das System tun muss, nicht wie es implementiert wird. Das ist entscheidend für Testbarkeit und Rückverfolgbarkeit. Beispiel:

Das System soll eine MySQL-Datenbank zur Speicherung von EKG-Daten verwenden.

Das beschreibt das Wie, nicht das Was. Die Wahl der Datenbank ist eine Designentscheidung, die in nachgelagerten Dokumenten wie dem Software Architecture Document (SAD) oder Detailed Design Document (DDD) festgelegt wird.

Anforderungen durch kontrollierte Sprache verbessern

Eine Möglichkeit, Mehrdeutigkeit zu reduzieren, ist die Einführung einer kontrollierten Sprache – einer vereinfachten Teilmenge des Englischen für technische Dokumentation. In der Luft- und Raumfahrt wird z. B. ASD-STE100 (Simplified Technical English) eingesetzt.

Kontrollierte Sprache erzwingt:

  • definierten Wortschatz
  • einfache Satzstrukturen
  • Vermeidung von Synonymen oder mehrdeutigen Begriffen

Mit einem Styleguide für kontrollierte Sprache lassen sich konsistente und leicht überprüfbare Anforderungen über mehrere Dokumente und Rollen hinweg erstellen.

Mehrdeutigkeit vermeiden

Mehrdeutigkeit kann entstehen durch lexikalische, syntaktische oder semantische Probleme:

  • Lexikalische Mehrdeutigkeit: Ein Wort hat mehrere Bedeutungen.
    Beispiel: „Bank“ kann Finanzinstitut oder Flussufer bedeuten.
  • Syntaktische Mehrdeutigkeit: Ein Satz erlaubt mehrere grammatikalische Strukturen mit unterschiedlicher Bedeutung.
    Beispiel: „Medizinische Geschichtsdatenbank“ – handelt es sich um eine Datenbank für Krankengeschichten oder um eine historische Datenbank aus Tibet?
  • Anbindungs-Mehrdeutigkeit: Eine Phrase (oft Präpositional) kann sich auf unterschiedliche Teile beziehen.
    Beispiel: „Der Zustandsautomat kann als Teil des Treibers für die Kommunikation mit der Watchdog-CPU implementiert werden.“
    Bedeutungen:
    • Der Treiber dient der Kommunikation und der Zustandsautomat ist Teil davon.
    • Der Zustandsautomat dient der Kommunikationssteuerung.
  • Semantische Mehrdeutigkeit: Ein Satz ist im Kontext unklar, auch ohne lexikalische oder syntaktische Probleme.
    Beispiel: „Das System soll den Motor stoppen, bevor er überhitzt.“ – Bezieht sich „er“ auf das System oder den Motor?

Mehrdeutigkeit schleicht sich oft durch vage Begriffe, Passivkonstruktionen oder unklare Referenzen ein. Beispiel:

„Das System soll das Warnsignal kurz nach Fehlererkennung aktivieren.“

Was bedeutet „kurz“? Wer aktiviert das Signal? Solche Fragen sind in einem sicherheitskritischen Kontext rote Flaggen.

Vermeiden Sie:

  • Relative Begriffe: leistungsfähig, akzeptabel, schnell, zuverlässig
  • Unklare Quantoren: alle, die meisten, einige, beliebig
  • Passiv: „wird aktiviert“ vs. „der Controller aktiviert“
  • Zeitliche Unschärfen: bald, periodisch, später
  • Doppelte Anforderungen: zwei „shall“ verbunden mit „und/oder“

Jede Anforderung muss atomar, verifizierbar und eindeutig sein.

Anforderungen formalisieren

Für höhere Sicherheitsstufen ist es notwendig, Anforderungen zu formalisieren. Das bedeutet, sie in eine formale Sprache wie PSL (Property Specification Language) oder LTL (Linear Temporal Logic) zu übersetzen, die Tools prüfen und simulieren können.

Formalisiertes Vorgehen ermöglicht:

  • vollständige Analyse von Randfällen
  • Rückverfolgbarkeit von High-Level-Anforderungen bis zur Implementierung
  • automatisierte Verifikation in Sicherheits-Audits

Praxisbeispiele

Infusionspumpe – Flussratenkontrolle

Natürliche Sprache (NL SR)

„Das System sollte die richtige Dosis mit der richtigen Geschwindigkeit abgeben.“

Probleme: Vage Begriffe wie „richtige Dosis“ und „richtige Geschwindigkeit“. Kein Subjekt definiert. Nicht testbar.

Kontrollierte natürliche Sprache (cNL SR)

„Wenn das Infusionsprogramm gestartet wird, soll die Steuereinheit das programmierte Medikamentenvolumen mit einer Flussrate zwischen 0,1 und 10,0 ml/h mit einer Genauigkeit von ±5 % abgeben.“

  • Subjekt: Steuereinheit
  • Aktion: soll abgeben
  • Parameter: Flussrate, Dosis, Genauigkeit
  • Auslöser: Start des Infusionsprogramms

Herzfrequenzmonitor – Alarm auslösen

Natürliche Sprache (NL SR)

„Das System muss einen Alarm auslösen, wenn die Herzfrequenz abnormal ist.“

Probleme: Was bedeutet „abnormal“? Wie laut oder schnell ist der Alarm? Wann genau soll er auslösen?

Kontrollierte natürliche Sprache (cNL SR)

„Wenn die Herzfrequenz des Patienten unter 40 bpm fällt oder 180 bpm überschreitet und dies länger als 3 Sekunden anhält, soll der Alarm-Controller innerhalb von 1 Sekunde einen 90-dB-Alarm auslösen.“

  • Klare Grenzwerte: 40 und 180 bpm
  • Zeitbedingung: länger als 3 Sekunden
  • Aktion: 90 dB Alarm aktivieren
  • Zeitgrenze: innerhalb 1 Sekunde

Strahlenbündelaktivierung mit Hardware-Interlock

Natürliche Sprache (NL SR)

„Das System soll den Strahl aktivieren, wenn der Bediener die Behandlung startet.“

Probleme:

  • Keine Erwähnung von Sicherheitsverriegelungen oder Bedingungen.
  • „Aktivieren“ ist unklar – physisch einschalten oder nur vorbereiten?

Kontrollierte natürliche Sprache (cNL SR)

„Das System soll den Strahlenbündel nur aktivieren, wenn der Ganty in der richtigen Position ist, der Hardware-Interlock geschlossen ist und die Behandlungskonsole einen gültigen ‚Start‘-Befehl vom Bediener erhält.“

  • Mehrere notwendige Bedingungen
  • Eindeutiges Subjekt und Auslöser
  • „Nur wenn“-Logik berücksichtigt Sicherheit

Anforderungsreview

Die Entwicklung eines sicherheitskritischen Produkts ist selten Aufgabe einer Einzelperson. Bevor die nächsten Schritte im V-Modell begonnen werden, müssen die Softwareanforderungen überprüft werden. Aber das ist Thema für das nächste Mal.

Weiterführende Literatur

]]>
Testen auf funktionale Sicherheit im Kontext der IEC 62304 Bernhard Trinnes https://bitcrushtesting.com/ https://bitcrushtesting.com/blog/iec62304_testing/ 2025-09-12T19:00:00Z 2025-09-12T19:00:00Z Bei der Entwicklung von Software für Medizinprodukte ist Sicherheit nicht nur ein Ziel, sondern eine rechtliche und ethische Verpflichtung. Unter den vielen Normen, die diesen Bereich regeln, sticht die IEC 62304 als zentrale internationale Norm für den Lebenszyklus von Medizinproduktesoftware hervor. Ein wesentlicher Teil der Konformität mit der IEC 62304 ist das systematische Testen auf funktionale Sicherheit. Doch was bedeutet das in der Praxis?

Als Ingenieure und Softwareentwickler sind wir darauf trainiert, in Strukturen, Zuverlässigkeit und Nachvollziehbarkeit zu denken. Diese Denkweise deckt sich eng mit der Philosophie der IEC 62304.

Funktionale Sicherheit verstehen

Funktionale Sicherheit stellt sicher, dass ein System korrekt auf seine Eingaben reagiert, insbesondere unter Fehlersituationen. Im medizinischen Bereich bedeutet das: Die Software darf weder Patienten noch Anwender gefährden, selbst im Falle vorhersehbarer Fehler.

Beispielsweise muss eine softwaregesteuerte Infusionspumpe, die Medikamente verabreicht, Sensorfehler, Kommunikationsausfälle und Anwenderfehler so behandeln, dass keine gefährlichen Ereignisse entstehen. Hier greift die funktionale Sicherheit.

IEC 62304 und Sicherheitsklassifizierung

Die IEC 62304 definiert drei Software-Sicherheitsklassen:

  • Klasse A: Keine Verletzung oder Gesundheitsschädigung möglich
  • Klasse B: Nicht schwerwiegende Verletzung möglich
  • Klasse C: Tod oder schwerwiegende Verletzung möglich

Abhängig von der Klassifizierung steigt der Umfang an Test- und Verifikationsaktivitäten erheblich. Für Software der Klasse C müssen umfassende Teststrategien umgesetzt werden, darunter Unit-Tests, Integrationstests und Systemverifikation mit Nachverfolgbarkeit bis hin zu den Risikokontrollen.

Die Rolle des Testens

Testen im Kontext der IEC 62304 bedeutet nicht nur, Fehler zu finden – es geht darum, nachzuweisen, dass die Software ihre Sicherheitsanforderungen unter allen vorhersehbaren Bedingungen erfüllt. Testen muss daher sein:

  • Systematisch: Nach einem dokumentierten und nachvollziehbaren Prozess
  • Risikobasiert: Tests werden nach potenzieller Schadenshöhe priorisiert
  • Bidirektional nachvollziehbar: Jeder Testfall ist einem Requirement zugeordnet und umgekehrt

Typische Testaktivitäten sind:

  • Statische Analyse zur frühzeitigen Erkennung potenzieller Fehler
  • Unit-Tests zur Verifizierung der Logik auf Funktionsebene
  • Integrationstests zur Sicherstellung der Kommunikation zwischen Modulen
  • Systemtests mit Fault-Injection und Grenzfällen
  • Verifikation der Risikokontrollen, insbesondere im Bereich Hardware-Software-Interaktion

Nachvollziehbarkeit

Wir sind bekannt für unsere Präzision und Dokumentationsstrenge – und in diesem Fall ist das von Vorteil. Die IEC 62304 fordert Nachvollziehbarkeit über den gesamten Software-Lebenszyklus. Jede Anforderung muss verknüpft sein mit:

  • Ihrem Ursprung im Risikomanagementprozess (typischerweise nach ISO 14971)
  • Dem entsprechenden Architektur- oder Designelement
  • Den Testfällen, die sie verifizieren

Werkzeuge wie Polarion, Codebeamer oder auch Open-Source-Alternativen wie ReqView und Robot Framework können diese Strenge unterstützen.

Integration mit ISO 14971 und IEC 60601

Testen auf funktionale Sicherheit darf nicht isoliert erfolgen. Es muss mit weiteren Normen abgestimmt sein, wie etwa:

  • ISO 14971 für Risikomanagement
  • IEC 60601 für elektrische Sicherheit und wesentliche Leistungsmerkmale

Beispielsweise könnte eine Software der Klasse C einen softwarebasierten Failsafe enthalten, der aktiviert wird, wenn ein Hardware-Sensor inkonsistente Daten meldet. Dieses Verhalten muss sowohl in der Software (simulierter Sensorfehler) als auch im Systemtest (tatsächliche Fehler-Injektion) geprüft werden.

Abschließende Gedanken

Testen auf funktionale Sicherheit nach IEC 62304 ist nicht nur ein regulatorisches Pflichtfeld – es ist eine Denkweise. Sie erfordert ein tiefes Verständnis sowohl der Softwarearchitektur als auch der klinischen Risiken.

Wir sind hier gut aufgestellt. Unser Fokus auf Prozessdisziplin, Risikomanagement und technische Integrität bietet eine solide Basis für die Entwicklung sicherer und zuverlässiger Medizintechnik-Software.

Am Ende geht es beim guten Testen nicht darum, jede Codezeile abzudecken – sondern darum, mit dem Wissen schlafen zu können, dass die Software niemanden gefährden wird.

]]>
Unit Tests mit Mehrwert Bernhard Trinnes https://bitcrushtesting.com/ https://bitcrushtesting.com/blog/unit-tests-that-add-value/ 2025-09-12T19:00:00Z 2025-09-12T19:00:00Z Unit Tests gehören zum Handwerkszeug professioneller Softwareentwicklung. Doch oft enden sie als lästige Pflichtübungen: Tests, die kaum etwas prüfen, bei Änderungen ständig brechen oder nur das Offensichtliche bestätigen. Damit Unit Tests echten Mehrwert liefern, braucht es Klarheit über Ziele und Nutzen.

Typische Probleme von Unit Tests

  • Triviale Tests: Sie prüfen nur Getter/Setter oder spiegeln die Implementierung Zeile für Zeile wider. Nutzen: null.
  • Fragile Tests: Schon kleine Refactorings führen zu Fehlschlägen, ohne dass sich das Verhalten geändert hat.
  • Fehlender Fokus: Tests prüfen Nebensächlichkeiten, aber nicht die fachlich wichtigen Regeln.
  • Unlesbarkeit: Komplexe Testlogik, die schwerer zu verstehen ist als der eigentliche Code.

Was macht Tests wertvoll?

Ein guter Unit Test erfüllt mindestens eine dieser Bedingungen:

  • Er deckt fachlich relevante Regeln ab (z. B. Preisberechnung, Sicherheitsprüfung).
  • Er erhöht Vertrauen in Refactorings, weil er Verhalten statt Implementierung testet.
  • Er dokumentiert beabsichtigtes Verhalten lesbar und nachvollziehbar.
  • Er liefert schnelles Feedback bei Fehlern.

Prinzipien für Mehrwert

  1. Teste Verhalten, nicht Implementation. Statt assertEquals(42, obj.getValue()) nur weil getValue() gerade 42 zurückgibt, lieber ein Szenario aufbauen, das fachlich Sinn ergibt.
  2. Halte Tests unabhängig. Jeder Test muss isoliert laufen können, ohne versteckte Abhängigkeiten.
  3. Benutze sprechende Namen. Ein Test mit Namen shouldRejectInvalidPassword() ist gleichzeitig Dokumentation.
  4. Edge Cases nicht vergessen. Fehlerfälle, Grenzwerte und Ausnahmen bringen oft mehr Erkenntnis als Happy-Path-Tests.
  5. Wartbarkeit bedenken. Tests sind Code und brauchen Pflege. Klare Strukturen und Hilfsfunktionen machen sie robust.

Beispiel: Wertvoller statt trivialer Test

Trivial:

TEST(UserTest, GetNameReturnsName) {
    User u("Alice");
    EXPECT_EQ("Alice", u.getName());
}

Kein echter Mehrwert, bestätigt nur, dass getName() zurückgibt, was im Konstruktor gesetzt wurde.

Mehrwert:

TEST(PasswordTest, RejectsShortPasswords) {
    User u("Alice");
    EXPECT_THROW(u.setPassword("123"), std::invalid_argument);
}

Dieser Test prüft eine Geschäftsregel: Passwörter müssen Mindestanforderungen erfüllen.

Fazit

Unit Tests mit Mehrwert konzentrieren sich auf Verhalten, Regeln und Robustheit. Sie sollen nicht die Implementierung abbilden, sondern Vertrauen schaffen und Wissen konservieren. Schlechte Tests sind Ballast, gute Tests sind Investitionen in Qualität und Wartbarkeit.

]]>