Hinweis zur Privatsphäre: Wenn Sie sich mit Ihrem GitHub-Konto anmelden, werden Ihre Quiz-Versuche in Google Firebase gespeichert, damit Sie Ihren Fortschritt verfolgen können. Diese Daten sind nur für den Kursleiter einsehbar, werden nicht anderweitig weitergegeben und nach Semesterende gelöscht. Frühere Löschung auf Anfrage beim Kursleiter. Möchten Sie anonym bleiben? Nutzen Sie den Gastmodus oder ein GitHub-Konto ohne Ihren echten Namen.
Lädt...

03 Übung: CFG Tracing

Punkte: 0 / 19

CFG Tracing Übung: Visualisierung von Statement- und Branch-Coverage

Einführung

Diese Übung hilft dir, Code-Coverage zu verstehen, indem du Testfälle durch Kontrollflussgraphen (CFGs) verfolgst. Durch die Visualisierung, welche Knoten (Anweisungen) und Kanten (Branches) abgedeckt werden, entwickelst du ein Gespür dafür, wie Coverage funktioniert.

Vorbereitung: Zuerst lesen

Bevor du diese Übung versuchst, studiere die folgenden Vorlesungsabschnitte:

Aus Kapitel 03 (Testtheorie und Coverage): Testtheorie & Coverage:

Lernziele

Nach Abschluss dieser Übungen solltest du in der Lage sein:

  • Kontrollflussgraphen zu lesen und zu interpretieren
  • Testfallausführung durch Code-Pfade zu verfolgen
  • Statement Coverage (C0) aus Knotenabdeckung zu berechnen
  • Branch Coverage (C1) aus Kantenabdeckung zu berechnen
  • Tests zu entwerfen, um spezifische Coverage-Ziele zu erreichen
  • Zu verstehen, warum C1 C0 subsumiert

Anleitung

  1. Studiere den Code und die CFG-Beschreibungen in jeder Frage
  2. Verfolge die gegebenen Testfälle durch den Graphen
  3. Identifiziere, welche Knoten und Kanten abgedeckt werden
  4. Berechne die Coverage-Prozentsätze
  5. Klicke, um nach dem Beantworten die Erklärungen anzuzeigen

Zeit: 35-45 Minuten für alle Übungen

Frage1 Einfaches CFG Tracing

Übung 1: Einfacher CFG - classify_number()

Betrachte diesen Code:

def classify_number(x):
    if x > 0:           # Node 1 (decision)
        return "pos"    # Node 2
    elif x < 0:         # Node 3 (decision)
        return "neg"    # Node 4
    else:
        return "zero"   # Node 5

Testfall:

def test_positive():
    assert classify_number(5) == "pos"

Mit Eingabe x = 5:

  • Pfad: START → N1 (True) → N2 → END
  • Abgedeckte Knoten: N1, N2 (2 von 5 Knoten)

Was ist die Statement Coverage (C0)? Gib eine Zahl ein (ohne %-Zeichen).

Frage2 Einfaches CFG Tracing

Übung 1: Einfacher CFG - classify_number() (Fortsetzung)

Gleicher Code und Test:

def test_positive():
    assert classify_number(5) == "pos"

Branch-Kanten (Entscheidungsergebnisse) im CFG:

  • N1 → N2 (True-Branch von x > 0)
  • N1 → N3 (False-Branch von x > 0)
  • N3 → N4 (True-Branch von x < 0)
  • N3 → N5 (False-Branch von x < 0)

Gesamte Branch-Kanten: 4

Der Test deckt nur N1 → N2 (True-Branch) ab.

Was ist die Branch Coverage (C1)? Gib eine Zahl ein (ohne %-Zeichen).

Frage3 Mehrere Testfälle

Übung 2: Mehrere Testfälle

Gleiche classify_number() Funktion, jetzt mit ZWEI Tests:

def test_positive():
    assert classify_number(5) == "pos"

def test_negative():
    assert classify_number(-3) == "neg"

Ablaufverfolgungen:

  • test_positive: START → N1 (True) → N2 → END (deckt N1, N2 ab)
  • test_negative: START → N1 (False) → N3 (True) → N4 → END (deckt N1, N3, N4 ab)

Kombiniert abgedeckte Knoten: N1, N2, N3, N4 (4 von 5)

Was ist die kombinierte Statement Coverage (C0)? Gib eine Zahl ein (ohne %-Zeichen).

Frage4 Mehrere Testfälle

Übung 2: Mehrere Testfälle (Fortsetzung)

Von beiden Tests abgedeckte Branch-Kanten:

  • N1 → N2 (True): ✓ von test_positive
  • N1 → N3 (False): ✓ von test_negative
  • N3 → N4 (True): ✓ von test_negative
  • N3 → N5 (False): ✗ nicht abgedeckt

Was ist die kombinierte Branch Coverage (C1)? Gib eine Zahl ein (ohne %-Zeichen).

Frage5 Mehrere Testfälle

Übung 2: Welcher Test wird für 100% Coverage benötigt?

Gegeben die zwei Tests (test_positive und test_negative), welcher zusätzliche Test würde 100% Branch Coverage erreichen?

Frage6 Mehrere Branches

Übung 3: calculate_grade() - Mehrere Branches

def calculate_grade(score):
    if score >= 90:         # N1
        return "A"          # N2
    elif score >= 80:       # N3
        return "B"          # N4
    elif score >= 70:       # N5
        return "C"          # N6
    elif score >= 60:       # N7
        return "D"          # N8
    else:
        return "F"          # N9

Zwei Tests:

def test_grade_A():
    assert calculate_grade(95) == "A"  # Pfad: N1(T) → N2

def test_grade_B():
    assert calculate_grade(85) == "B"  # Pfad: N1(F) → N3(T) → N4

Diese Funktion hat 4 Entscheidungspunkte (N1, N3, N5, N7), jeder mit True/False-Ergebnis. Gesamte Branches: 8

Abgedeckte Branches:

  • N1 True: ✓, N1 False: ✓, N3 True: ✓, N3 False: ✗
  • N5 True: ✗, N5 False: ✗, N7 True: ✗, N7 False: ✗

Was ist die Branch Coverage (C1)? Gib den Prozentsatz als Dezimalzahl ein (z.B. 37.5).

Frage7 Mehrere Branches

Übung 3: Wie viele weitere Tests werden benötigt?

Um 100% Branch Coverage (C1) für calculate_grade() zu erreichen, wie viele ZUSÄTZLICHE Tests werden über die zwei bereits vorhandenen (test_grade_A und test_grade_B) hinaus benötigt?

Gib eine Zahl ein.

Frage8 C0 vs C1 Beziehung

Übung 4: C0 vs C1 Vergleich

def check_eligibility(age, has_license):
    if age >= 18:               # N1
        if has_license:         # N2
            return "approved"   # N3
        return "need license"   # N4
    return "too young"          # N5

Zwei Tests:

def test_approved():
    assert check_eligibility(25, True) == "approved"
    # Pfad: N1(T) → N2(T) → N3

def test_need_license():
    assert check_eligibility(20, False) == "need license"
    # Pfad: N1(T) → N2(F) → N4

Coverage-Ergebnisse:

  • C0: 4/5 Knoten = 80% (N1, N2, N3, N4 abgedeckt; N5 nicht abgedeckt)
  • C1: 3/4 Branches = 75% (N1 True, N2 True, N2 False abgedeckt; N1 False nicht abgedeckt)

Welche Aussage über C0 und C1 ist korrekt?

Frage9 Verschachtelte Bedingungen

Übung 5: Verschachtelte Bedingungen - validate_password()

def validate_password(password):
    if len(password) < 8:           # N1
        return "too short"          # N2
    has_upper = any(c.isupper() for c in password)  # N3
    has_digit = any(c.isdigit() for c in password)  # N4
    if not has_upper:               # N5
        return "need uppercase"     # N6
    if not has_digit:               # N7
        return "need digit"         # N8
    return "valid"                  # N9

Test:

def test_valid_password():
    assert validate_password("SecurePass1") == "valid"

Ablaufverfolgung: “SecurePass1” hat Länge 11, Großbuchstaben und eine Ziffer. Pfad: N1(F) → N3 → N4 → N5(F) → N7(F) → N9

Abgedeckte Knoten: N1, N3, N4, N5, N7, N9 (6 von 9)

Was ist C0? Gib eine Zahl ein (ohne %-Zeichen, auf die nächste ganze Zahl gerundet).

Frage10 Verschachtelte Bedingungen

Übung 5: Verschachtelte Bedingungen (Fortsetzung)

Gleicher Test für validate_password():

Entscheidungsergebnisse:

  • N1 (len < 8): True = NICHT abgedeckt, False = Abgedeckt ✓
  • N5 (not has_upper): True = NICHT abgedeckt, False = Abgedeckt ✓
  • N7 (not has_digit): True = NICHT abgedeckt, False = Abgedeckt ✓

Was ist C1? Gib eine Zahl ein (ohne %-Zeichen).

Frage11 Verschachtelte Bedingungen

Übung 5: Welche Tests werden für 100% C1 benötigt?

Wähle ALLE Tests aus, die helfen würden, 100% Branch Coverage für validate_password() zu erreichen:

Wählen Sie alle zutreffenden Optionen:

Frage12 Early Returns

Übung 6: Early Returns - calculate_discount()

def calculate_discount(amount, is_member, coupon_code):
    if amount <= 0:                     # N1
        return 0                        # N2
    discount = 0                        # N3
    if is_member:                       # N4
        discount += 10                  # N5
    if coupon_code == "SAVE20":         # N6
        discount += 20                  # N7
    elif coupon_code == "SAVE10":       # N8
        discount += 10                  # N9
    return amount * (discount / 100)   # N10

Zwei Tests:

def test_member_with_save20():
    result = calculate_discount(100, True, "SAVE20")
    # Pfad: N1(F) → N3 → N4(T) → N5 → N6(T) → N7 → N10

def test_non_member_no_coupon():
    result = calculate_discount(100, False, None)
    # Pfad: N1(F) → N3 → N4(F) → N6(F) → N8(F) → N10

Abgedeckte Knoten: N1, N3, N4, N5, N6, N7, N8, N10 (8 von 10)

Was ist C0? Gib eine Zahl ein (ohne %-Zeichen).

Frage13 Early Returns

Übung 6: Welche Branches sind NICHT abgedeckt?

Gleiche Tests wie oben. Wähle ALLE nicht abgedeckten Branches:

Wählen Sie alle zutreffenden Optionen:

Frage14 Komplexe Bedingungen

Übung 7: Komplexe Bedingungen - approve_loan()

def approve_loan(income, credit_score, has_collateral):
    if income < 30000:                          # N1
        return "rejected: low income"           # N2
    if credit_score < 600:                      # N3
        return "rejected: poor credit"          # N4
    if income >= 100000 and credit_score >= 750:  # N5
        return "approved: premium"              # N6
    if credit_score >= 700 or has_collateral:   # N7
        return "approved: standard"             # N8
    return "manual review required"             # N9

Drei Tests:

def test_premium_approval():
    assert approve_loan(150000, 800, False) == "approved: premium"
    # Pfad: N1(F) → N3(F) → N5(T) → N6

def test_standard_with_good_credit():
    assert approve_loan(50000, 720, False) == "approved: standard"
    # Pfad: N1(F) → N3(F) → N5(F) → N7(T) → N8

def test_standard_with_collateral():
    assert approve_loan(50000, 650, True) == "approved: standard"
    # Pfad: N1(F) → N3(F) → N5(F) → N7(T) → N8

Abgedeckte Knoten: N1, N3, N5, N6, N7, N8 (6 von 9)

Was ist C0? Gib eine Zahl ein (ohne %-Zeichen, auf die nächste ganze Zahl gerundet).

Frage15 Komplexe Bedingungen

Übung 7: Komplexe Bedingungen (Fortsetzung)

Branch-Ergebnisse:

  • N1 (income < 30k): True = ✗, False = ✓
  • N3 (credit < 600): True = ✗, False = ✓
  • N5 (income>=100k AND credit>=750): True = ✓, False = ✓
  • N7 (credit>=700 OR collateral): True = ✓, False = ✗

Was ist C1? Gib den Prozentsatz als Dezimalzahl ein (z.B. 62.5).

Frage16 Testentwurf

Übung 8: Entwirf deine eigenen Tests

def process_order(total, user_type, promo_code):
    if total <= 0:                          # N1
        return "invalid order"              # N2
    base_discount = 0                       # N3
    if user_type == "premium":              # N4
        base_discount = 15                  # N5
    elif user_type == "member":             # N6
        base_discount = 5                   # N7
    if promo_code == "FLASH50":             # N8
        if total >= 100:                    # N9
            return f"discount: 50%"         # N10
        return "promo requires $100+"       # N11
    if base_discount > 0:                   # N12
        return f"discount: {base_discount}%"  # N13
    return "no discount"                    # N14

Wie viele Entscheidungspunkte (if/elif Anweisungen) hat dieser Code?

Gib eine Zahl ein.

Frage17 Testentwurf

Übung 8: Minimale Tests für 100% C1

Die process_order() Funktion hat 6 Entscheidungspunkte mit 12 Branches insgesamt.

Was ist die minimale Anzahl an Tests für 100% Branch Coverage (C1)?

Gib eine Zahl ein.

Frage18 Coverage-Beziehungen

Zusammenfassung: C1 subsumiert C0

Basierend auf den Übungen, welche Aussage über Coverage-Beziehungen ist WAHR?

Frage19 CFG-Erkenntnisse

Zusammenfassung: Wichtigste Erkenntnis aus dem CFG Tracing

Was ist die wichtigste Erkenntnis aus dem Verfolgen von Tests durch Kontrollflussgraphen?

© 2026 Dominik Mueller   •  Powered by Soopr   •  Theme  Moonwalk