Dichte und Testüberlappung für Codeabdeckung
Von Parasoft
14. September 2011
4 min lesen
Das Konzept der Bedeckungsdichte hängt etwas mit der Testüberlappung zusammen. Im Allgemeinen möchten Sie vermeiden, dass mehrere Testfälle dieselbe Funktionalität testen (dh die Testüberlappung minimieren).
Die Idee hinter diesem Prinzip ist, dass Testfälle nicht nur aufgrund von Fehlern im Code, sondern häufiger aufgrund von Änderungen in der Spezifikation unterbrochen werden. Code-Verhalten, das zuvor als korrekt angenommen wurde, kann aufgrund neuer Anforderungen falsch oder unzureichend werden. Wenn der Code geändert wird, um die neue Anforderung widerzuspiegeln, können die Testfälle, die das alte Verhalten bestätigen, unterbrochen werden und müssen aktualisiert werden. Wenn Sie einen TDD-Ansatz verfolgen, sollte die Aktualisierung der Testfälle tatsächlich erfolgen, bevor der getestete Code geändert wird. In einer Testsuite mit einem hohen Grad an Testüberlappung kann eine kleine Änderung der Spezifikation (und Implementierung) erfordern, dass eine große Anzahl von Testfällen aktualisiert wird. In einer solchen Situation überlappten sich die Testfälle offensichtlich in einigen Codedetails, die sich ändern konnten. Solche Vorkommnisse sind höchst unerwünscht, da sie die Wartungskosten der Testsuite erheblich erhöhen.
Äquivalenzklassen
Die Minimierung der Testüberlappung hängt eng mit dem mathematischen Konzept einer sogenannten Äquivalenzklasse zusammen. In vereinfachten mathematischen Begriffen ist eine Äquivalenzklasse eine Menge von Elementen, die gemäß einer bestimmten Beziehung alle einander äquivalent sind. Diese Idee ist auch für die Testabdeckung relevant.
Wir haben zuvor vier verschiedene Codepfade für die in Listing 2 gezeigte getestete Methode identifiziert. Wenn Sie sich die Codelogik genauer ansehen, werden Sie feststellen, dass nur die zwei niedrigstwertigen Bits der Eingabe ausgewertet werden. Die verbleibenden Bits der Eingabe haben keinen Einfluss auf den verwendeten Codepfad. Wenn Sie also die Methode mit einem Eingabewert von 4 testen, wird effektiv derselbe Codepfad verwendet, der für einen Eingabewert von 0 verwendet wird. Auf die gleiche Weise verursachen die Eingabewerte 1, 5, 9, 13, ... alle die gleicher Codepfad genommen werden. Zum Zwecke der Pfadabdeckung weist die Methode aus Listing 2 vier Äquivalenzklassen auf, die in Tabelle 2 zusammengefasst sind.
Tabelle 2: Äquivalenzklassen für die Pfadabdeckung von Listing 2
Um eine vollständige Pfadabdeckung mit minimaler Testüberlappung zu erreichen, reicht es aus, einen Eingabewert aus jeder Äquivalenzklasse auszuwählen. In Bezug auf die Abdeckung ist nichts zu gewinnen, wenn mehrere Testfälle Eingabewerte aus derselben Äquivalenzklasse verwenden. Die Äquivalenzklassen variieren je nach Abdeckungskriterium. In Bezug auf die Anweisungsabdeckung befinden sich die Eingabewerte 0 und 2 beide in der Äquivalenzklasse zum Abdecken der return null-Anweisung der Beispielmethode, sie würden sich jedoch in verschiedenen Äquivalenzklassen befinden, wenn die Pfadabdeckung betrachtet wird.
Das Identifizieren von Äquivalenzklassen für Testeingaben ist ein nützliches Werkzeug zur Minimierung von Testüberschneidungen, aber auch hier drohen Probleme, wenn wir uns einer vollständigen Regressionsabdeckung nähern. Wenn eine Testsuite eine vollständige Regressionsabdeckung für eine bestimmte Methode erreicht, bedeutet dies, dass die Testsuite eine vollständige Spezifikation dieser Methode bildet. Jede noch so geringfügige Änderung des Verhaltens der Methode würde zu einem Testfehler führen. Für die Beispielmethode aus Listing 2 haben wir bereits festgestellt, dass Testfälle mit allen 256 möglichen Eingabewerten erforderlich sind. Wie viele Äquivalenzklassen für Testeingaben würde es in Bezug auf die vollständige Regressionsabdeckung geben? Leider lautet die Antwort auf diese Frage "256".
Für eine vollständige Regressionsabdeckung entspricht kein Eingabewert einem anderen Eingabewert. Vollständige Regressionsabdeckung bedeutet, dass das Verhalten einer Methode vollständig „gesperrt“ ist. Obwohl sich die Eingabewerte 0 und 4 zum Zweck der Pfadabdeckung in derselben Äquivalenzklasse befinden, befinden sie sich beispielsweise für eine vollständige Regressionsabdeckung in eigenen Äquivalenzklassen. Wenn sie sich in derselben Äquivalenzklasse befinden, würde dies bedeuten, dass die Auswahl eines der Werte (z. B. 4) immer noch das Kriterium der vollständigen Regressionsabdeckung erfüllt. In diesem Fall wäre es jedoch möglich, die getestete Methode so zu implementieren, dass sie für die Eingabe von 4, jedoch nicht für die Eingabe von 0 ordnungsgemäß funktioniert (z. B. durch Hinzufügen einer Prüfung, die absichtlich ein falsches Ergebnis zurückgibt, wenn die Eingabe war 0). Daher können 0 und 4 für eine vollständige Regressionsabdeckung nicht in derselben Äquivalenzklasse liegen.
Codeabdeckungsdichte
Wenn eine vollständige Regressionsabdeckung angestrebt wird, kann der Trick, nur eine Eingabe aus jeder Äquivalenzklasse auszuwählen, nicht mehr zur Minimierung der Testüberlappung verwendet werden. Eine vollständige Regressionsabdeckung führt immer zu zusätzlichen Überlappungen. Welche anderen Prinzipien können verwendet werden, um die negativen Auswirkungen von Testüberschneidungen zu mildern?
Ein häufiges Problem ist allgemeiner Code, der direkt oder indirekt von einer großen Anzahl von Testfällen ausgeführt wird. Spezifikationsänderungen, die sich auf diesen allgemeinen Code auswirken, verursachen wahrscheinlich eine große Anzahl von Fehlern. Ziel ist es, solche Konzentrationen zu vermeiden und die Tests so umzuschreiben, dass die Menge des häufig ausgeführten Codes begrenzt wird. Die Abdeckungsdichte ist eine hilfreiche Metrik, mit der Testsuiten erstellt werden können, die den getesteten Code gleichmäßiger ausführen. Die Abdeckungsdichte erweitert die Dichotomie von "abgedeckt" gegenüber "nicht abgedeckt" auf eine numerische Metrik, die auch zählt, wie oft ein Zweig oder Pfad ausgeführt wird. Anstatt beispielsweise nur eine Ja- oder Nein-Antwort zu erhalten, ob eine bestimmte Leitung abgedeckt ist, zeigt die Abdeckungsdichte auch an, dass die Leitung genau 500 Mal ausgeführt wurde. Die Abdeckungsdichte kann auf jedes Abdeckungskriterium angewendet werden, wird jedoch am häufigsten in Verbindung mit einer Anweisungs- oder Zweigabdeckung angeboten.
Auch hier ist die Visualisierung der Pfadabdeckungsdichten genauso problematisch wie die Visualisierung der einfachen Ja / Nein-Pfadabdeckung. Eine übliche Methode zur Visualisierung der Abdeckungsdichte besteht darin, im Quellcode-Editor farbige Markierungen mit unterschiedlicher Helligkeit hinzuzufügen. Ein heller Grünton könnte beispielsweise darauf hinweisen, dass ein Teil des Codes von einigen Testfällen abgedeckt wird. Ein extrem dunkler Grünton wäre jedoch eine Warnung, dass es eine große Konzentration von Testfällen gibt, die alle denselben bestimmten Teil ausführen von Code. Solche Warnindikatoren sollten idealerweise zu einem Refactoring führen, bei dem der gemeinsame Code aus dem Codepfad entfernt wird.
***
Bildquelle: Jen und eine Kamera