Software-Prüfläufe beschleunigen Auf die Reihung kommt es an

Automatische Firmware-Tests laufen oft auf teuren Anlagen und dauern mitunter mehrere Tage. Entwickler möchten die Zeit vom Start der Umgebung bis zum Bug Report minimieren. Aber das ist gar nicht so einfach.

Ein Steuergerätehersteller aus Bayern kämpft mit einer Herausforderung, die den Zweck der Technik, über die der Artikel berichtet, sehr gut beschreibt: Die Ausführungszeit der umfangreichen Systemtests des Herstellers dauert bereits länger als eine Woche. Und das, obwohl die Firma bereits mehrere Systeme parallel im Einsatz hat. Das Unternehmen hat jedoch den Anspruch von Continuous Testing – vom Test-Team fordern die Entwickler eine qualifizierte Rückmeldung zu jeder Code-Änderung innerhalb weniger als 24 Stunden. Ein weiteres Vervielfachen der bestehenden Prüfsysteme scheidet aus Kostengründen aus. Vor etwas mehr als drei Jahren ist es der Firma mithilfe von Data Mining und künstlicher Intelligenz (KI) in Zusammenarbeit mit der technischen Universität München (TUM) gelungen, einen Scheduler zu schreiben. Er wählt mit hoher Wahrscheinlichkeit die Tests zum Ausführen zuerst aus, die tatsächlich einen Fehler finden könnten.

Somit gelang es in weniger als 24 Stunden mit hoher Wahrscheinlichkeit nach einer Code-Änderung alle neuen Fehler zu finden ohne weitere Systeme anzuschaffen. Im Laufe der Zeit hat das Unternehmen die KI-Methoden mit der sogenannten Test-Impact-Analyse ersetzt, die im Artikel noch näher vorgestellt wird. Es ist erforderlich, beim momentanen Stand der Technik, den gesamten Quellcode zu instrumentieren und die Abdeckung von Systemprüfungen zu erfassen. Das kann sehr aufwendig oder, bei verteilten Systemen oder Systemen, die mit FPGAs realisiert sind,  unmöglich sein. Folgende Zeilen präsentieren einen einfacheren Ansatz, der ohne KI und ohne Instrumentierung mithilfe von Statistiken arbeitet und sich der genaueren Test-Impact-Analyse annähert.

Rahmenbedingungen des Testnutzens

Beim Unternehmen Riedel Communications am Standort Wien wurde der folgende Ansatz entwickelt. Wie das Team des bayrischen Steuergeräteherstellers kämpfen die Entwickler dort auch oft mit subtilen Bugs in Messgeräten und Funktionsgeneratoren. Zusätzlich zu den Testresultaten »Passed« und »Failed« hat das Team das Resultat »Error« eingeführt. Das dritte Urteil bedeutet, dass ein Messgerät nicht antwortet oder unplausible Werte liefert und daher kein zuverlässiges Urteil abgibt. Ein Beispiel für ein Error ist, wenn das über Ethernet ferngesteuerte Oszilloskop nicht antwortet oder statt eines Messwertes »NaN« (Not a Number) liefert. Es kann sein, dass das System Under Test (SUT, zu testendes System) dennoch fehlerfrei ist, es kann jedoch genauso gut das Gegenteil der Fall sein.

Zum Sichern der Logs auf einem File-Server speichert das Team in Wien das Resultat jeder Ausführung, das Datum, die Version der Firmware-Under-Test sowie die Laufzeit in einer SQL-Datenbank. Das ist eine ganz wichtige Voraussetzung für die Testreihung auf Basis von statistischen Auswertungen. Bevor ein Stapel von Systemtests gestartet wird, überprüft die Umgebung mithilfe von Funktionsgeneratoren, Messgeräten und (De)multiplexern, ob alle Kabel korrekt angesteckt sind und ob die Messgeräte erwartungsgemäß reagieren. Es ist wichtig, um keine falschen Ergebnisse zu erhalten, nur weil sich ein Kollege das Oszilloskop ausgeborgt hatte und nach dem Zurückbringen falsch angesteckt hat.

Rahmenbedingungen beim Bug Lifecycle

Für jeden Bug, den das Team findet, wird ein eigenes Ticket in einem Bug Tracker angelegt (im konkreten Fall ist das Jira). Der Bug Tracker ist mit der Code-Versionsverwaltung (hier Bitbucket) integriert. In jedem Bug Report notiert das Team jene Prüfläufe, die wegen des Bugs fehlschlagen. Ein Beispiel zeigt Bild 1. Ursprünglich wurden die Test-IDs in den Reports notiert, um ein erstes Überprüfen des Bugfixes zu erleichtern: Die im Ticket notierten Ausführungen (meist ist es jedoch nur eine) werden ausgeführt um den Bugfix zu verifizieren.

Wenn das Entwicklungsteam einen Bugfix ins Code Repository einpflegt, wird die Ticket-Nummer des Bugs beim Commit in die Code-Versionsverwaltung angegeben. Gleichsam das »Begründen« für eine Code-Änderung ohne neuen Entwicklungsauftrag. Mithilfe der Integration der Versionsverwaltung mit dem Bug Tracker ist die für den Bugfix nötige Code-Änderung auf die Weise im Bug Ticket ersichtlich.

Strategien zum Priorisieren

Aktuelle akademische Publikationen zum Thema Testreihung (engl. Test Case Priorization, TCP) nennen verschiedene Strategien. Unter anderem das schnelle Erreichen einer hohen Abdeckung von Anforderungen oder das schnelle Erreichen einer hohen Abdeckung von Code [1]. Beide Strategien mögen für ein erstes Ausführen gut anwendbar und nützlich sein, haben jedoch gravierende Nachteile im viel häufigeren Anwendungsfall: beim Regressionstest nach einer Code-Änderung oder -Erweiterung. Eine schnell erreichte hohe Abdeckung von Anforderungen oder Code muss nicht heißen, dass schnell (neue) Fehler entdeckt werden, denn die mit der Strategie zuerst abgedeckten Code-Teile könnten völlig entkoppelt von den letzten Code-Änderungen sein. Für die Regressionsprüfung ist eine Reihung gefragt, die jene Tests zuerst aufruft, die die höchste Wahrscheinlichkeit haben, neu eingebrachte Fehler zu finden. Die meisten wissenschaftlichen Publikationen zum Thema Effizienz handeln daher von der Reihung im Regressionsfall.
Um Reihungen zu vergleichen, hat sich in akademischen Publikationen das Maß Average Percentage of Faults Detected (APFD) etabliert - hier Formel 1:

In der Formel ist m die Anzahl der auffindbaren Fehler im System und n die Anzahl der Tests. TFi ist die Position des Tests, der Fehler i aufdeckt [2]. Diese Maßzahl zur Position in der Reihung erreicht dann 100 Prozent, wenn zuerst alle Prüfungen laufen, die Fehler finden, und erst danach die »Blindgänger-Tests«. APFD berücksichtigt jedoch keine Kosten, also die Laufzeit. Sie kann beträchtlich zwischen den Prüfungen variieren. Um die Laufzeiten zu berücksichtigen, wurde das Maß APFDc, Average Percentage of Faults Detected per Cost, ins Leben gerufen. Eine riesige, komplizierte Formel, die jedoch die Schwere eines Fehlers nicht berücksichtigen kann. Es ist daher für den industriellen Anwender schwer zu sagen, ob eine Reihung, die einer anderen um drei Prozentpunkte überlegen ist, tatsächlich die nützlichere Reihung ist.