Wie viel Code Coverage ist genug?

Code Coverage ist ein wichtiger Maßstab für die Qualität von Software Tests. Aber wie viel Abdeckung ist für Ihr Projekt wirklich sinnvoll?

Lesezeit:
6 min
Wie viel Code Coverage ist genug?

Code Coverage ist eine Metrik, die misst, welcher Anteil des Codes durch Tests abgedeckt wird – aber was sagt eine hohe Abdeckung tatsächlich über die Qualität Ihrer Software aus? Eine hohe Testabdeckung kann die Fehlerrate senken, aber ist eine 100%ige Abdeckung immer sinnvoll? Dieser Artikel beleuchtet, wie Code Coverage funktioniert, welche Tools dafür verfügbar sind und warum eine durchdachte Teststrategie oft entscheidender ist als das Erreichen eines bestimmten Prozentsatzes. Erfahren Sie, welche Abdeckungsziele sinnvoll sind und wie Sie eine Balance zwischen Aufwand und Codequalität finden.

Was ist Code Coverage?

In der Softwareentwicklung sind Metriken quantitative Maßstäbe, die verwendet werden, um die Qualität und Effizienz von Code zu bewerten. Code Coverage ist in diesem Zusammenhang eine wichtige Metrik, die misst, wie viel Ihres Codes durch Tests abgedeckt wird.

In der Regel wird die Codeabdeckung als Prozentsatz der Anzahl der durch einen Test oder eine Sammlung von Tests abgedeckten Zeilen (Line Coverage) definiert. Es gibt auch andere, teils weniger gebräuchliche Arten, wie Branch Coverage, Function Coverage, Statement Coverage oder Condition Coverage (auch Predicate Coverage genannt). Ermittelt werden die Metriken dann anhand des Verhältnis der getesteten Elemente (Zeilen, Statements etc.) und der ungetesteten Elemente. Sind beispielsweise von 120 Code-Zeilen durch Unittests 96 Zeilen abgedeckt, dann ergibt sich eine Line Coverage von 80 %.

Messung der Code-Abdeckung ist Teil der Qualitätssicherung von Software. Eine hohe Testabdeckung bedeutet, dass ein großer Teil des Codes getestet wurde, was die Wahrscheinlichkeit von Fehlern verringert und die Qualität des Codes erhöht. Die Analyse der Testabdeckung zeigt, welche Teile des Codes nicht getestet wurden. Dadurch können Tests gezielt erweitert werden, um die Abdeckung zu erhöhen. In CI/CD-Pipelines kann die Code Coverage als Metrik verwendet werden, um sicherzustellen, dass der Code kontinuierlich gut getestet wird. So können z.B. Merge Requests abgelehnt werden, wenn diese die Code Coverage des Gesamtprojekts verringern würden.

Wie erhebt man Code Coverage?

Abhängig von der Programmiersprache und den verwendeten Tools gibt es verschiedene Möglichkeiten, Code Coverage zu erheben. In der Regel wird ein spezielles Tool oder eine Bibliothek verwendet, die die Ausführung des Codes während der Tests überwacht und die abgedeckten Branches, Statements oder Zeilen zählt. Einige gängige Tools für verschiedene Programmiersprachen sind:

Wie hoch sollte meine Code Coverage sein?

Die ideale Code Coverage (hier Line Coverage) ist fast eine philosophische Frage und kann von Projekt zu Projekt variieren. Sie hängt von mehreren Faktoren ab, einschließlich der Art des Projekts, den mit Fehlern verbundenen Risiken und den Praktiken des Entwicklungsteams. Es gibt jedoch einige allgemeine Richtlinien und Überlegungen, die bei der Festlegung eines Zielwertes für die Code Coverage hilfreich sein können.

Weit verbreitet sind diese beiden Richtlinien:

Die durchschnittliche Codeabdeckung in Softwareprojekten kann variieren, aber Studien bieten einige Einblicke. So ergab eine Analyse von 1.270 Open-Source-Projekten mit TravisCI im Jahr 2019, dass die durchschnittliche Codeabdeckung 78 % betrug, wobei Ruby-Projekte eine höhere Abdeckung (86 %) als Java-Projekte (63 %) aufwiesen. Eine andere Studie über 100 große Open-Source-Java-Projekte gab keinen Durchschnittswert an, zeigte aber, dass die Codeabdeckung nicht signifikant mit der Anzahl der nach der Veröffentlichung auftretenden Fehler korreliert.

Während eine hohe Code Coverage generell angestrebt werden sollte, kann sie deshalb nie das alleinige Kriterium für die Qualität der Tests sein. Es ist wichtig, auch die Tiefe und die Qualität der Tests zu berücksichtigen. Tests sollten nicht nur darauf abzielen, eine hohe Abdeckung zu erreichen, sondern auch sicherstellen, dass sie sinnvolle und relevante Szenarien abdecken. Insbesondere das Testen von Grenzfällen ist entscheidend, um die Robustheit und Zuverlässigkeit einer Anwendung sicherzustellen. In der Praxis kann eine pragmatische Herangehensweise mit einem Zielwert von etwa 80-90% und einer höheren Abdeckung in kritischen Bereichen eine gute Balance darstellen.

Hohe Coverage liefert keine Aussage über Testqualität

Hohe Coverage kann trügerisch sein, wenn wichtige Randbedingungen oder Fehlerfälle nicht getestet werden. Ein einfaches Beispiel hierfür ist die Division zweier Zahlen. Man betrachte dazu folgendes Beispiel in der Programmiersprache Rust:

// src/lib.rs
fn divide(a: i32, b: i32) -> i32 {
    a / b
}

#[test]
fn test_divide() {
    assert_eq!(divide(42, 2), 21);
}

Durch die Funktion test_divide wird mit Tarpaulin eine 100%ige Coverage erreicht, da alle Zeilen des Codes ausgeführt werden:

cargo tarpaulin
...
INFO cargo_tarpaulin::report: Coverage Results:
|| Uncovered Lines:
|| Tested/Total Lines:
|| src/lib.rs: 2/2
|| 
100.00% coverage, 2/2 lines covered, +0.00% change in coverage

Offensichtlich ist dieser Test alleine jedoch unzureichend, da er nicht den Fall einer Division durch Null abdeckt.

fn main() {
    let result = divide(42, 0);
    println!("Result is: {result}");
}

Wird diese Funktion mit b = 0 aufgerufen, erhalten wir einen Laufzeitfehler und das Programm stürzt ab.

cargo run --release
...
thread 'main' panicked at src/lib.rs:2:5:
attempt to divide by zero
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Neben solchen Randbedingen sind auch Seiteneffekte wie das Schreiben in eine Datenbank oder das Senden von E-Mails wichtige Aspekte, die nicht von Code Coverage allein abgedeckt werden. Entsprechend sollte Code Coverage immer in Kombination mit anderen Qualitätsmetriken und einer sinnvollen Teststrategie betrachtet werden.

Integration in Gitlab CI/CD

Ein häufiger Anwendungsfall für Code Coverage ist die Integration in CI/CD-Pipelines. Hier ein Beispiel für eine Gitlab CI/CD-Konfiguration, die Tarpaulin für die Coverage eines Rust-Projekts verwendet:

# .gitlab-ci.yml
test:
  image: xd009642/tarpaulin
  script:
    - cargo tarpaulin --all-features --out xml
  coverage: /\d+.\d+% coverage/
  artifacts:
      reports:
        coverage_report:
          coverage_format: cobertura
          path: cobertura.xml

Weitere Beispiele für das Einbinden in GitHub Actions und CircleCI finden sich in der Tarpaulin-Dokumentation.

GitLab ermöglicht es, die Code Coverage direkt in der Merge-Request-Ansicht zu visualisieren. So können Entwickler und Reviewer auf einen Blick sehen, ob die Coverage durch den Merge Request beeinflusst wird. Alternativ erlauben Tools wie Tarpaulin auch die Generierung von HTML-Reports, die auch die lokale Visualisierung von Coverage erlauben.

Fazit

Code Coverage ist ein wertvolles Werkzeug, aber keine Garantie für fehlerfreie Software. Eine hohe Abdeckung kann Ihnen helfen, viele Codepfade abzudecken, doch es sollte nicht Ihr einziges Ziel sein. Entwickeln Sie stattdessen eine gezielte, risikobasierte Teststrategie, die kritische Szenarien und Randfälle berücksichtigt. Mit einem realistischen Abdeckungsziel von etwa 80–90% und besonders hoher Coverage in sicherheitsrelevanten Bereichen erreichen Sie die optimale Balance aus Testtiefe und Effizienz – und stellen damit die Qualität und Zuverlässigkeit Ihrer Software sicher.

Experten kontaktieren

Sie haben weitere Fragen zum Thema oder benötigen konkrete Hilfe? Schreiben Sie uns eine Nachricht oder vereinbaren Sie direkt einen Termin für ein Gespräch.

Weiterlesen

Zum Blog