Herausforderung Embedded Devices

Testabdeckung bei kleinen Targets

6. August 2018, 14:57 Uhr | Manne Kreuzer
Diesen Artikel anhören

Fortsetzung des Artikels von Teil 1

Code-Coverage-Analyser

Verifysoft Technology
Testwell-CTC++-Report mit Coverage-Informationen im Quellcode: Die Bedingung in Zeile 11 wurde zehnmal als „falsch“ ausgewertet und nie als „wahr“. Zur vollständigen Testabdeckung wäre dies noch nachzuholen
© Verifysoft Technology

Um die Testabdeckung zu ermitteln, werden Code-Coverage-Analyser eingesetzt. Dazu ergänzen sie den Code vor der Übergabe an den Compiler mit Zählern für die gewünschten Testebenen. Diesen Vorgang bezeichnet man als das Instrumentieren des Codes. Ein sehr einfaches Werkzeug dafür ist zum Beispiel das GNU-Coverage-Test-Tool gcov. Mittels der gcc-Option -ftest-coverage kann der Code instrumentiert werden, um zu ermitteln, wie oft jede Code-Zeile ausgeführt wurde. Die Option -fprofile-arcs instrumentiert die Verzweigungen. »Um erste Erfahrungen auf dem Gebiet der Code-Coverage zu machen oder für kleine Projekte ist dieses Tool auf jeden Fall geeignet«, erklärt Klaus Lambertz. »Sein Nachteil ist – neben dem Fehlen von anspruchsvollen Testabdeckungsstufen, die für größere Testing-Anforderungen benötigt werden – die Aufbereitung und Interpretation der gewonnenen Informationen. Hier sind kommerzielle Tools deutlich überlegen.«

passend zum Thema

Die professionellen Lösungen arbeiten nach dem gleichen Grundprinzip und instrumentieren den Code. Die Zähler werden in der Regel als globale Arrays abgelegt. Wann und wie diese Zähler dann verändert werden, hängt von der geforderten Code-Coverage-Stufe ab. Das folgende Beispiel einer in C geschriebenen While-Bedingung macht deutlich, welche Konsequenzen die unumgängliche Instrumentierung hat:
while (! b == 0 )
{
     r = a % b;
     a = b;
     b = r;
}
result = a;

Durch die Instrumentierung – in diesem Fall mit dem Code-Coverage-Werkzeug Testwell CTC++ – ergibt sich folgende Struktur:
while ( (( ! b == 0 ) ? (ctc_t[23]++, 1) : (ctc_f[23]++, 0)) )

{
    r = a % b ;
    a = b ;
    b = r ;
}
result = a ;

Durch die Instrumentierung wächst der Code. Die benötigten Arrays befinden sich im Datenspeicher, sowohl im RAM als auch im ROM sind zusätzliche Kapazitäten notwendig. Auch beeinflusst die Instrumentierung die Ausführungszeit. Bei Server- oder PC-Anwendungen kann dieser Effekt vernachlässigt werden. Bei Embedded-Geräten hingegen oft nicht, da die Hardware-Ressourcen aus Kostengründen häufig sehr knapp kalkuliert sind. »Hier ist darauf zu achten, einen Code-Coverage-Analyser mit einem vergleichsweise geringen In­strumentierungs-Overhead zu nutzen, da die Zähler sonst schnell die Grenzen des verfügbaren Speichers sprengen«, erläutert Klaus Lambertz. »Das gilt insbesondere, wenn sehr anspruchsvolle Testabdeckungsstufen wie MC/DC erforderlich sind.«

Verifysoft Technology
Durch die von Testwell CTC++ angebotene Bit-Coverage lässt sich der RAM-Bedarf signifikant reduzieren.
© Bilder: Verifysoft Technology

Sollte das Code-Coverage-Tool einen zu hohen Instrumentation-Overhead haben, kann diese Hürde beim RAM mit der partiellen Instrumentierung umgangen werden. Dabei werden nur kleine Ausschnitte des zu testenden Programms instrumentiert und getestet. Der Test wird nacheinander mit allen Programmteilen wiederholt, die daraus gewonnenen Daten werden zu einem Gesamtbild zusammengefügt. Dadurch kann die Testabdeckung für das vollständige Programm ermittelt werden. Ein anderer Ansatz auf kleinen Targets ist, die Größe der Zähler zu beschränken.

Normalerweise arbeiten Code-Coverage-Werkzeuge mit 32-bit-Zählern. Diese können zumindest theoretisch auf 16 oder 8 bit reduziert werden. Hierbei sollte man aber Vorsicht walten lassen, denn unter Umständen können die Zähler dann überlaufen. Die gewonnenen Daten müssen also mit großer Sorgfalt interpretiert werden. In extremen Fällen können die Zähler zudem auf einzelne Bits gesenkt werden. Diese Bit-Coverage kann zum Beispiel dann sinnvoll sein, wenn es nicht relevant ist, wie oft ein Programmabschnitt durchlaufen wurde.

Auch die gewählte Coverage-Stufe beeinflusst die Anforderungen an das verfügbare RAM. Der zusätzlich benötigte Platz im ROM hingegen lässt sich kaum begrenzen. Zur Erfassung der Code-Coverage ist eine kleine Bibliothek erforderlich, die unter anderem für die Übertragung der Zählerstände an einen Host zuständig ist. Neben dem Speicher belastet die Instrumentierung auch den Prozessor im Target. Hierdurch kann es vorkommen, dass ein definiertes Timing nicht mehr eingehalten wird. Besonders wenn die CPU bereits eng am Limit arbeitet, können fehlerhafte Abläufe auftreten. »Die Buskommunikation ist dafür besonders anfällig. Hier sollte der Tester aufmerksam den Ablauf überwachen und die Ergebnisse sorgfältig prüfen«, rät Klaus Lambertz. »Leistungsfähige Code-Coverage-Tools sind jedoch in der Lage, den Speicherbedarf für die Instrumentierung sowie die Änderungen des Laufzeitverhaltens relativ gering zu halten.«

Testing und die Ermittlung der Testabdeckung werden im Embedded-Umfeld deutlich an Bedeutung gewinnen, denn die Software-Qualität wird immer wichtiger. Auch wenn sicher nicht alle Normen und Standards langfristig eine 100-prozentige MC/DC-Coverage für jede Art von Software zu verlangen: Es ist nur eine Frage der Zeit, bis die Standardisierungsgremien und Branchenverbände die Anforderungen auch abseits der sicherheitskritischen Anwendungen erhöhen. Bessere Tests sind aber auch im Interesse der Hersteller selbst. Denn fehlerhafte Produkte verursachen hohe Folgekosten, vom eigenen Ruf ganz abgesehen. »Die vom PC bekannte Bananen-Software, die erst beim Nutzer reift, werden die Kunden im Embedded-Bereich kaum akzeptieren wollen«, resümiert Klaus Lambertz.


  1. Testabdeckung bei kleinen Targets
  2. Code-Coverage-Analyser

Lesen Sie mehr zum Thema


Jetzt kostenfreie Newsletter bestellen!

Weitere Artikel zu Verifysoft Technology