Unittests und Coverage – Wie viel Testabdeckung brauche ich?

Björn Schmitz

08/09/2018

Unit Tests sind schon etwas Tolles! Unit Tests werden in der Regel vom Entwickler selber parallel zur Entwicklung geschrieben. Es wird nicht zwingend zusätzliches Testpersonal benötigt (auch wenn es schwer zu empfehlen ist weitere Personen beim Softwaretest hinzuzuziehen). Außerdem werden hierbei schon sehr früh in der Entwicklung Fehler aufgedeckt und unter Umständen werden diese Fehler sogar bis auf die verursachenden Zeilen im Code eingegrenzt. Fehler, die hierbei gefunden werden, müssen daher nicht später in aufwendigen Debug Sessions gesucht werden. Das gilt natürlich auch für statische Code-Analyse und Code-Reviews. Zumindest gegenüber dem Code Review allerdings, haben Unittests den Vorteil, dass diese automatisierbar sind, und somit Fehler aufgrund von Codeänderungen ganz von alleine finden. Wenn Unit Tests also wirklich so klasse sind, sollte man denken:

„je mehr Code Zeilen ich als Entwickler damit abdecke, desto mehr Fehler finde ich logischerweise“

Sollte man denken…

Was ist eigentlich coverage?

Erst einmal etwas Theorie: Coverage bezeichnet den Grad, zu dem eine Software durch Tests abgedeckt wird. In der Regel wird dies ausgedrückt in Prozent. Dabei gibt es verschiedene Möglichkeiten coverage zu berechnen. Zwei der gängigsten sind dabei:

  • Statement-coverage: Der prozentuale Anteil an abgedeckten statements im Code.
  • Branch-coverage: Der prozentuale Anteil der beim Test durchlaufenen Verzweigungen.

Als Beispiel: Gibt es in einem switch-case einen default-case, in dem wirklich nichts passiert (natürlich sollte hier mindestens ein Kommentar stehen, der erklärt warum hier nichts passieren muss), so muss dieser default-case beim Test nicht durchlaufen werden, um die statement-coverage auf 100 % zu treiben. Es ist ja schließlich kein statement enthalten. Für branch-coverage muss jedoch bei jeder Entscheidung jeder mögliche Ausgang getestet werden. Das heißt in unserem switch-case Beispiel muss jeder case durchlaufen werden um zu 100 % statement-coverage zu gelangen. Ein weiteres Beispiel zeigt die Abbildung unten. Das Bild zeigt eine Coverage Berechnung der Funktion „testFunction“. Grün hinterlegte Zeilen wurden bei mindestens einem Test durchlaufen. Rot hinterlegte hingegen wurden bei keinem Test durchlaufen. Bezogen auf die erste if-else-Anweisung (Zeile 14-19) ergibt sich ein Statement-coverage von 100 %, da alle statements durchlaufen wurden. Die Branch-coverage für diesen Bereich liegt hingegen nur bei 50 %. Bei der zweiten if-else-Anweisung (Zeile 21-26) ergibt sich jeweils eine Statement- und Branch-coverage von 50 %. Darüber hinaus gibt es noch weitere Möglichkeiten – wie „function-coverage“ oder „modified condition/decision coverage“ – um die Testabdeckung von Unit Tests zu berechnen. Auf diese möchte ich der Einfachheit halber an dieser Stelle allerdings nicht eingehen.

Das Problem mit der coverage

Vor kurzem habe ich in einem Projekt gearbeitet, in dem die Prozesse des Kunden 100 % Statement coverage forderten. Die meisten anderen Entwickler, denen ich davon erzählte reagierten geschockt: „Was, sowas gibt es?“. „…aber ergibt sowas Sinn?“

Ja sowas gibt es natürlich! Aber Sinn macht es aus folgenden Gründen nicht unbedingt:

Wer immer in der Planung von Projekten beschäftigt ist, scheint grundsätzlich zu wenig Zeit für Software-Tests einzuplanen. Warum das so ist, füllt sicher einen weiteren Blog Beitrag. Aber die Konsequenzen liegen auf der Hand. Schreiben die Prozesse 100% coverage (egal welche man hier zur Berechnung heranzieht), bedeutet dies erst einmal einen gigantischen Berg Arbeit, den der Entwickler kaum abarbeiten kann. Zumindest nicht, wenn er seine Arbeit gewissenhaft verrichten will (nehmen wir an dieser Stelle an, der Entwickler schreibt die Unittests für seinen Code selbst). Zum Glück liefern ihm die Prozesse aber auch direkt einen Ausweg! Gefordert sind lediglich x % statement- und eventuell y % branch-coverage. Wie diese erreicht werden sollen, schreibt in der Regel keiner vor. In einer idealen Welt würde sich ein Entwickler natürlich trotzdem gewissenhaft jedem Unit Test widmen. Auch wenn die nur öde völlig linear geschrieben getter-Funktionen testen, bei denen man jeden Fehler schon von weitem sieht. In der Praxis bleibt ihm dafür aber entweder gar keine Zeit, oder das Schreiben von lauter völlig unnützen Unit Tests lässt den Entwickler soweit abstumpfen, dass er das Schreiben solcher Tests als äußerst nervige Pflicht empfindet.  Eine hohe coverage führt so ggf. eher dazu, dass die Qualität des einzelnen Testcases sinkt. Schließlich fragt am Ende keiner mehr, ob der Test mehr als

„3 = 3 ?“

abprüft. Zumindest nicht, wenn das automatisch generierte Protokoll eine schön hohe coverage ausspuckt und diese Zahl dann sogar noch mit grüner Farbe hinterlegt.

Ihr Ansprechpartner:

M.Sc. Björn Schmitz, Software Entwickler
E-Mail: schmitz@medtech-ingenieur.de
Tel.:  +49 9131 691 240
 

Benötigen Sie Unterstützung bei der Entwicklung Ihres Medizingeräts? Wir helfen gerne! Die MEDtech Ingenieur GmbH bietet Hardware-Entwicklung, Software-Entwicklung, Systems Engineering, Mechanik-Entwicklung und Beratung aus einer Hand. Nehmen Sie Kontakt mit uns auf.

Kontakt aufnehmen

Test Abdeckung ist demnach also nicht unbedingt ein Maß dafür wie wenig Fehler eine Software enthält. Zu einem ähnlichen Ergebnis kam auch eine Arbeit der Universität Göteborg zusammen mit Ericsson. Diese wurde unter dem Titel „Mythical Unit Test Coverage“ veröffentlicht und beschreibt eine Studie, bei der versucht wurde eine Korrelation zwischen Unit Test coverage und fehlerfreiem Code zu finden. Eine klare Korrelation zwischen Testabdeckung und gefundenen Fehlern stellten die Autoren nicht fest. Es wurde aber sehr wohl eine Korrelation zwischen Komplexität, Größe der Softwaredateien (line of Code), sowie Anzahl der Code-Änderungen und den gefundenen Fehlern festgestellt. Es könnte also viel wirkungsvoller sein, in das Einhalten der Kodierrichtlinien, gut gekapselten Code, und eine klare Softwarearchitektur (die natürlich auch eingehalten werden sollte) zu investieren, als exzessives Unit Testing zu Betreiben.

Warum halten sich coverage Softwaremetriken trotzdem?

Diese Frage ist im Prinzip einfach zu beantworten. Die Sinnhaftigkeit von Tests lässt sich nur messen, wenn man sich intensiv in den Source Code eingräbt und diesen versteht. Eine Zahl im Protokoll gegen den Sollwert abzugleichen ist selbstverständlich deutlich einfacher. Wenn später dann ein Fehler im Feld Auftritt kann man auf dieses Protokoll verweisen und sagen „wir haben nach bestem Wissen und Gewissen unsere Software getestet. Mit Fehlern konnten wir daher unmöglich rechnen“. Das sichert einen natürlich ab und im besten Fall erreicht man mit der erzwungenen Testabdeckung einen gewissen „Minimalstandard“. Einen fehlerfreien Code erreicht man hiermit aber sicher nicht.

Was kann man besser machen?

Hier wird es knifflig. Wichtige Bausteine für einen (möglichst) fehlerfreien Code sind die bereits angesprochenen Maßnahmen:

  • Geringe Code-Komplexität
  • Gute Kapselung von Software und keine überdimensional großen Softwaredateien
  • Eine klare und gut durchdachte Softwarearchitektur, die auch vom Entwickler eingehalten wird (und deren Einhaltung selbstverständlich über Code-Reviews überprüft wird)

Darüber hinaus sollte auf Unit Tests – aus den eingangs Beschrieben und natürlich völlig unstrittigen Vorteilen – nicht verzichtet werden. Mein Vorschlag wäre allerdings für ein Projekt (oder besser für alle Softwareprojekte in einem Unternehmen) ein Konzept zu erarbeiten, was getestet werden sollte. Das kann zum Beispiel über eine Checkliste erfolgen:

Implementiert die Funktion Risikomaßnahme?  –> testen

Könnte die Funktion bei einem Fehlverhalten zu einem Schaden des Anwenders führen –> testen

Bei einem Code Review (das in der Regel eh durchgeführt werden muss) überprüft dann ein Entwickler – der den Code NICHT geschrieben hat – ob jede Funktion, die ins Raster fällt auch einen entsprechenden Test hat. Dies ermöglicht den Entwicklern sich auf das Wesentliche zu konzentrieren. Wer es genauer wissen will, führt stichprobenartig ein Review der Unit Tests durch. Werden hier viele Probleme gefunden, erweitert man das Suchraster. Führt man diesen Prozess kontinuierlich begleitend zur Entwicklung durch, wird der Entwickler ganz von alleine anfangen, bessere Tests zu schreiben.

Natürlich könnte man sich jetzt vorstellen, dass die Reviewer beim Aufdecken von Fehlern vorsichtig sind, um es sich nicht mit dem Entwickler zu verscherzen. Oder die Entwickler sprechen sich sogar ab, was bei den Stichproben gereviewed wird. Das halte ich persönlich für sehr unwahrscheinlich. Schließlich wollen die wenigsten Entwickler fehlerhaften Code produzieren. Es kann aber natürlich nicht völlig ausgeschlossen werden. Um solche Bedenken zu zerstreuen empfehle ich zum Review oder zum Schreiben der Tests einfach externe Kräfte zu verwenden, z.B. ein Entwickler aus einer anderen Abteilung. Falls kein entsprechender Entwickler im Unternehmen zur Hand ist, kann es auch sinnvoll sein, einen externen Dienstleister zu beauftragen. Solch ein externer Tester hat unter anderem folgende Vorteile:

  • Der Tester kennt den Entwickler nicht persönlich und kann Code und Unit Tests daher mit einer gewissen Neutralität begegnen.
  • Der Tester sieht Softwarearchitektur und Kodierrichtlinien zum ersten Mal und hat sich noch nicht daran gewöhnt, wenn sich gewisse Abweichungen in der Entwicklergruppe eingebürgert haben.
  • Ein projektinterner Entwickler, der den Code eines anderen reviewed, könnte sich davor fürchten zu viele Fehler aufzudecken die ihn „pedantisch“ erscheinen lassen. Denn dies könnte wiederum dazu führen, dass der Autor sich das nächste Mal rächt und den Code des Testers ebenso kritisch auseinandernimmt. Ein externer Tester hat dieses Problem natürlich nicht.
  • Ein externer Entwickler als Tester, der sonst nicht mit den Entwicklern zusammenarbeitet, vergleicht automatisch Entwicklungsprozesse und die entwickelte Software mit den Prozessen und dem Code aus anderen Projekten. So findet er eventuell Schwachstellen, welche die projektinternen Entwickler übersehen.

Fazit

Unit Tests sind eine wichtige Säule im Software-Test, die früh und zielgerichtet Fehler aufdecken kann. Die Testabdeckung alleine sagt allerdings nichts über die Qualität des Codes aus. Ein Testkonzept, das ausschließlich auf hohe Testabdeckung setzt, kann unter Umständen sogar die Qualität der einzelnen Tests verschlechtern. Wichtiger ist es ein gutes Testkonzept zu entwickeln und festzulegen, wer was zu testen hat und wer dies überprüft. Ein (Projekt-) externer Softwaretester ist dabei immer hilfreich. Es bleibt jedoch dabei: Das beste Rezept für fehlerfreien Code ist eine gute Softwarearchitektur, die in gut lesbare und nicht übertrieben komplexe Softwaremodule übersetzt wird.


Geschrieben von Björn Schmitz

Seit Juli 2017 gehöre ich zum MEDtech-Ingenieur Team und bin hier vor allem als Firmwareentwickler tätig. Schon in kürzester Zeit konnte ich an vielen spannenden Projekten aus dem Bereich Medizintechnik, aber auch aus anderen Bereichen mitwirken.


Weitere Beiträge

  • 29/01/2025
  • Allgemein, Hardware, Testen

Einleitung Um bei der EMV Prüfung für die Zulassung neuer medizintechnischer Geräte das Risiko zu reduzieren machen wir gerne Vortests mit den Geräten in der Prototypen Phase. Aktuell unterstützen ...

Weiterlesen
  • 12/11/2024
  • Allgemein, Software, Testen, Tools

In sicherheitskritischen Softwareprojekten steht die Qualität der Software an erster Stelle. Besonders bei Klasse-C-Software, die nach strengen Normen wie IEC 62304 (Medizintechnik) zertifiziert werden muss, ist es essenziell, dass ...

Weiterlesen
  • 08/08/2024
  • Allgemein, Elektrostimulation, Software, Testen

Heutzutage sind Apps im Gesundheitsbereich sehr wichtig. Besonders Apps, die Daten von medizinischen Sensoren lesen und verarbeiten können, sind nützlich. Flutter ist ein Open-Source-Framework von Google, das sich hervorragend ...

Weiterlesen
Cookie-Übersicht

Die Internetseiten der MEDtech Ingenieur GmbH verwenden Cookies. Cookies sind Textdateien, welche über einen Internetbrowser auf einem Computersystem abgelegt und gespeichert werden.

Zahlreiche Internetseiten und Server verwenden Cookies. Viele Cookies enthalten eine sogenannte Cookie-ID. Eine Cookie-ID ist eine eindeutige Kennung des Cookies. Sie besteht aus einer Zeichenfolge, durch welche Internetseiten und Server dem konkreten Internetbrowser zugeordnet werden können, in dem das Cookie gespeichert wurde. Dies ermöglicht es den besuchten Internetseiten und Servern, den individuellen Browser der betroffenen Person von anderen Internetbrowsern, die andere Cookies enthalten, zu unterscheiden. Ein bestimmter Internetbrowser kann über die eindeutige Cookie-ID wiedererkannt und identifiziert werden.

Durch den Einsatz von Cookies kann die MEDtech Ingenieur GmbH den Nutzern dieser Internetseite nutzerfreundlichere Services bereitstellen, die ohne die Cookie-Setzung nicht möglich wären.

Mittels eines Cookies können die Informationen und Angebote auf unserer Internetseite im Sinne des Benutzers optimiert werden. Cookies ermöglichen uns, wie bereits erwähnt, die Benutzer unserer Internetseite wiederzuerkennen. Zweck dieser Wiedererkennung ist es, den Nutzern die Verwendung unserer Internetseite zu erleichtern. Der Benutzer einer Internetseite, die Cookies verwendet, muss beispielsweise nicht bei jedem Besuch der Internetseite erneut seine Zugangsdaten eingeben, weil dies von der Internetseite und dem auf dem Computersystem des Benutzers abgelegten Cookie übernommen wird.

Die betroffene Person kann die Setzung von Cookies durch unsere Internetseite jederzeit mittels einer entsprechenden Einstellung des genutzten Internetbrowsers verhindern und damit der Setzung von Cookies dauerhaft widersprechen. Ferner können bereits gesetzte Cookies jederzeit über einen Internetbrowser oder andere Softwareprogramme gelöscht werden. Dies ist in allen gängigen Internetbrowsern möglich. Deaktiviert die betroffene Person die Setzung von Cookies in dem genutzten Internetbrowser, sind unter Umständen nicht alle Funktionen unserer Internetseite vollumfänglich nutzbar.

Weitere Informationen erhalten Sie in unserer Datenschutzerklärung.

Unbedingt notwendige Cookies

Dieses Cookie wird benötigt, um Ihre Cookie-Einstellungen zu merken und weitere Hauptfunktionen zur Verfügung zu stellen

Um Ihnen eine Auskunft über Ihre gespeicherten personenbezogenen Daten hier (https://medtech-ingenieur.de/gespeicherte-daten-2/) geben zu können, benötigen wir einen Cookie, um Sie bei der Datenabfrage identifizieren zu können. Dieser Cookie muss aus Sicherheitsgründen deshalb aktiviert sein. Ein weiterer Cookie wird gesetzt, um diesen Banner nicht erneut anzeigen zu müssen.

Cookie-Name Beschreibung
PHPSESSID Name: PHP session
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Wir benötigt, um Sie bei der Anfrage von personenbezogenen Daten identifizieren zu können. Das Cookie wird nur gesetzt, wenn Sie eine Anfrage hier (https://medtech-ingenieur.de/gespeicherte-daten-2/) stellen.
Laufzeit: Sitzungsende
Kategorie: Unbedingt notwendige Cookies
moove_gdpr_popup Name: Cookie-Box Einstellungen
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Wird benötigt, um Ihre Cookie-Einstellungen zu speichern, um den Cookie-Banner nicht erneut anzeigen zu müssen.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
comment_author_9c90e388e3e1be4a6c594fa6ac8a3eec
comment_author_email_9c90e388e3e1be4a6c594fa6ac8a3eec
comment_author_url_9c90e388e3e1be4a6c594fa6ac8a3eec
Name: Kommentar Einstellungen
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Cookie wird angelegt, wenn Sie ein Kommentar auf MEDtech Ingenieur veröffentlichen wollen, um Sie als Autor identifizieren und den aktuellen Status Ihres Kommentars anzeigen zu können. Das Cookie enthält den angegebenen Namen. Das Cookie wird erst gesetzt, wenn Sie der Speicherung Ihrer personenbezogenen Daten zustimmen.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
rmp-rate Name: RMP Rate
Anbieter: Eigentümer der Webseite (MEDtech Ingenieur)
Zweck: Cookie wird angelegt, wenn Sie eine Bewertung eines Blogbeitrags mithilfe des Sternebewertungssystems abgeben. Ihnen wird eine anonymisierte ID zugewiesen, um zu erkennen, ob Sie einen Artikel bereits bewertet haben oder nicht. Das Cookie wird nur verwendet, um zu verhindern, dass mehrfache Bewertung abgegeben werden und erst gesetzt, wenn Sie auf einen Stern klicken.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
medtech-download-page Name: Download Page
Anbieter: Eigentümer der Webseite (MEDtech Ingenieur)
Zweck: Cookie wird angelegt, wenn Sie den Landing-Page Prozess erfolgreich durchlaufen haben. Dies geschieht nur, wenn Sie einen Content-Download von unserer Website anstreben.
Laufzeit: 1/2 Jahr
Kategorie: Unbedingt notwendige Cookies