Versandkostenrechner-Übungsaufgabe zur Testfallerstellung nach Whitebox-Systematik

https://bildung.social/@oerinformatik/111523080351425661

https://oer-informatik.de/whitebox-testfall-uebung-shippingcost

tl/dr; (ca. 60 min Bearbeitungszeit): Zu einer gegebenen Funktion (Versandkostenrechner) soll ein Kontrollflussgraph erstellt werden, die McCabe-Zahl berechnet werden (beides optional), die Überdeckungsmetriken für einen bestehenden Test berechnet werden, weitere Tests aus Whitebox-Sicht ergänzt werden und alles mit einem Code-Coverage-Tool implementiert werden. (Zuletzt geändert am 06.12.2023)

Die Aufgaben beziehen sich auf die Inhalte der folgenden Blogposts:

Aufgabe Überdeckungstests Versandkostenrechner

Gegeben ist die folgende Methode, zur Berechnung von Versandkosten.

Die Methode erhält ein Array von Bestellpositionen und errechnet in Abhängigkeit von Positionsanzahl und Einzelgewicht die Versandkosten. Die Bestellpositionen haben folgende Struktur (für uns relevant sind nur die Getter für Anzahl (quantity) und Gewicht (weight):

UML-Klassendiagramm der Klasse Shipping mit genannten Gettern und Settern
UML-Klassendiagramm der Klasse Shipping mit genannten Gettern und Settern

Hinweis: Da einige Antworten bereits Lösungen für die folgenden Fragen enthalten, ist es ratsam, zunächst alle Fragen zu beantworten / bearbeiten und dann die Lösungen anzuschauen. Jedenfalls dann, wenn man auch etwas dazulernen will…

  1. (Optional vorneweg): Erstelle für die Methode shippingCalculator() einen Kontrollflussgraphen!

    Der Kontrollfluss lässt sich wie folgt darstellen (aufwändige kommentierte Fassung - eigentlich sind nur Knoten und Kanten erforderlich):

    Kontrollflussgraph für die Methode shippingCalculator() (11 Knoten, 5 Verzweigungen)
    Kontrollflussgraph für die Methode shippingCalculator() (11 Knoten, 5 Verzweigungen)

    Eine kleine Gemeinheit hier ist die Short-Circuit-Evaluation (die zusammengesetzte Bedingung mit dem ||-Operator): Bei der Bedingung ((totalWeight >10) || (shippingCost >50)) wird der zweite Teil (shippingCost >50) nur ausgewertet, wenn der erste Teil (totalWeight >10) false ergibt. Wenn sich die Bedingungen lediglich aus Werten zusammensetzen ist das unerhelblich, wenn die Bedingungen selbst Methodenaufrufe sind, beeinflusst das den Kontrollfluss jedoch entscheidend.

  2. (Optional vorneweg): Berechne für die Methode shippingCalculator() die zyklomatisch Komplexität (McCabe-Zahl)!

    Der Kontrollfluss weist 5 binäre Verzweigungen auf, somit ergibt sich die McCabe-Zahl zu

    M = b + 1 = 5 + 1 = 6

    (Hinweis: wenn man die Short-Circuit-Evaluation nicht einbezieht / sieht sind es lediglich 4 binäre Verzweigungen.)
  3. Welche Anweisungs- und Zweigüberdeckung erreicht folgender Testfall? Gibt die Werte in der Form xx von yy an (oder als nicht gekürzter Bruch), und nicht als Prozentzahl!

    Es werden die beiden Anweisungen shippingCost += 0.3; und shippingCost = 50; nicht erreicht (Knoten 4 und 10 im Kontrollflussgraphen). Insgesamt sind es – je nach Zählweise - 11 Anweisungen/Anweisungsblöcke => 9/11=81%.

    Kontrollflussgraph für die Methode shippingCalculator() mit 9 (von 11) überdeckten Knoten und überdeckten Zweigen (1 komplett, 3 teilweise)
    Kontrollflussgraph für die Methode shippingCalculator() mit 9 (von 11) überdeckten Knoten und überdeckten Zweigen (1 komplett, 3 teilweise)

    Wie bei allen Überdeckungsmetriken gilt auch hier: der Bruch ist aussagekräftiger als die Prozentzahl, weil man Einblicke in die Berechnung bekommt.

    JaCoCo zählt atomare Instruktionen und kommt auf 65/72 = 90%)

    Die Übersichts-Ausgabe von JaCoCo zeigt 90% Anweisungsüberdeckung
    Die Übersichts-Ausgabe von JaCoCo zeigt 90% Anweisungsüberdeckung

    Im Detail werden folgende Zeilen/Zweige nicht erreicht:

    Im eingefärbten Code von JaCoCo sind 6 Anweisungen erreicht (grün), eine Verzweigung voll abgedeckt (grüne Raute) und drei Verzweigungen teilweise überdeckt (gelbe Raute)
    Im eingefärbten Code von JaCoCo sind 6 Anweisungen erreicht (grün), eine Verzweigung voll abgedeckt (grüne Raute) und drei Verzweigungen teilweise überdeckt (gelbe Raute)

    Es werden die Zweige (pos.getQuantity()*pos.getWeight() < 0.5) (Kante c, Knoten 3)und else (Kante h, Knoten 5) sowie ((totalWeight >10) || (shippingCost >50)) nicht erreicht (Kanten j und l zu Knoten 10). Insgesamt sind es 8 Zweige (von denen 3 nicht erreicht werden), wenn man die Short-Ciruit-Bedingung (s.u.) bedenkt sind es sogar 10 Branches (von denen 4 nicht erreicht werden) => 5/8 = 62,5% bzw. 6/10 = 60%

    Eine kleine Gemeinheit hier ist, dass bei der Bedingung ((totalWeight >10) || (shippingCost >50)) der zweite Teil (shippingCost >50) nur ausgewertet wird, wenn der erste Teil (totalWeight >10) false ergibt. Wenn sich die Bedingungen wie hier lediglich aus Werten zusammensetzen ist das unerhelblich.

    Es wäre jedoch auch denkbar, dass die Bedingungsabfrage in Methoden ausgelagert wird:

    Nach dieser Refaktorisierung ändert sich der Kontrollfluss abhängig davon, ob die erste Bedingung als true ausgewertet wird oder nicht. sindKostenUeberMaximum() würde ggf. nie aufgerufen und müsste über einen weiteren Test gesondert überdeckt werden.
  4. Ergänze so wenige Testfälle wie möglich (zusätzlich zu dem in b) genannten), um 100%ige Anweisungsüberdeckung zu erhalten. Als Antwort langt es, für die Testfälle nur den Parameter positions zu definieren (also den given-Abschnitt des obigen Tests). Das erwartete Ergebnis muss nicht berechnet werden. Das Antwortbeispiel für den obigen Testfall wäre:

    Es fehlen Tests für die beiden Anweisungen shippingCost += 0.3; und shippingCost = 50; (Knoten 4 und 10 im Kontrollflussgraphen). Um sie zu erreichen benötigen wir eine sehr leichte und eine sehr schwere ShippingPosition.

    Denkbar wäre, diese in einem einzigen Testfall zu übergeben:

    Jedoch überschreibt der Sperrgut-Versandpreis den Preis für leichte Lieferungen. Sinnvoller ist es also, beides gesondert zu testen (auch wenn die Aufgabenstellung hier eine Lösung in einem Test zuließe).

    Zwei komplett ausgeschriebene Testfälle mit erwartetem Ergebnis wären:

  5. Ergänze so wenige Testfälle zusätzlich zu denen aus c) und d) wie möglich, um 100%ige Zweigüberdeckung zu erhalten. Als Antwort langt es wieder, für die Testfälle nur den Parameter positions zu definieren (also den given-Abschnitt des obigen Tests). Das erwartete Ergebnis muss nicht berechnet werden. Das Antwortbeispiel für den obigen Testfall wäre:

    Nach dem ersten Testfall in c) fehlten die Zweige (pos.getQuantity()*pos.getWeight() < 0.5) (Kante c, Knoten 3) und else (Kante h, Knoten 5) sowie ((totalWeight >10) || (shippingCost >50)) (Kanten j und l zu Knoten 10).

    Mit den Testfällen aus d) sind beide Zweige von Knoten 3 komplett überdeckt (die leichte Lieferung) sowie die Kante j und h (die schwere Lieferung).

    Wenn wir die Short-Circuit-Bedingung ausser Acht lassen, wären wir also bereits fertig, denn es fehlt nur noch diese Kante (l).

    Wir benötigen also einen Testfall, bei dem das Gesamtgewicht unter 10, die Versandkosten trotzdem über 50 liegen. Das kann durch viele, sehr leichte Artikel erreicht werden:

    Als ausgeschriebener Testfall mit erwartetem Ergebnis wäre das:

  6. Übernimm die Methode in eine IDE und erstelle die entworfenen Testfälle. Überprüfe Deine Ergebnisse mit JaCoCo.

  7. Versuche Äquivalenzklassen und Grenzfälle aus Blackboxsicht für die FUnktion zu erstellen, in dem Du die Anforderungen aus dem Code extrahierst. Welchen logischen Fehler gibt es im Code, der mit Whitebox-Systematik nicht gefunden werden konnte?

    Es werden zwar Versandkosten für Menge*Gewicht < 0.5 und Menge*Gewicht < 2.5 angesetzt, sobald der Wert aber über 2.5 steigt werden keine weitere Kosten fällig (erst ab einem Gesamtgewicht ab 10).

    Whiteboxtest können derartige Spezifikationsprobleme nicht aufdecken, hierzu wäre eine gesonderte Blackbox-Betrachtung hilfreich: das Aufzeichnen von Äquivalenzklassen deckt derlei Lücken in der Spezifikation auf.

Weiter Übungsaufgaben

Links zu weiteren Übungsaufgaben finden sich über das Menü oder am Ende des Artikels zu Whitebox-Tests/Code-Coverage


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: Versandkostenrechner-Übungsaufgabe zur Testfallerstellung nach Whitebox-Systematik” von Hannes Stein, Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/whitebox-testfall-uebung-shippingcost veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/qs/code-coverage. Stand: 06.12.2023.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: