0%

Ein echtes Projekt testen · Übung

Dateiverhalten isoliert testen

Auswahltests haben keine dauerhaften Auswirkungen. Ein JSON-Schreiber schon. Ein sinnvoller Test muss deshalb festlegen, wo diese Bytes entstehen dürfen. Eine feste selected.json im Projekt würde Tests von altem Zustand abhängig machen und Dateien zurücklassen.

Pytest stellt jedem Test, der danach fragt, einen neuen Path namens tmp_path bereit. Ergänze diesen Test des Dateiverhaltens:

import json

from catalog import write_catalog_json


def test_json_file_keeps_visible_unicode(tmp_path):
    # Arrange
    output_path = tmp_path / "catalog-output.json"
    item = {
        "sku": "CAFE-7",
        "name": "Café Cards",
        "quantity": 7,
        "unit_price": 2.5,
        "in_stock": True,
    }

    # Act
    write_catalog_json([item], output_path)
    raw = output_path.read_text(encoding="utf-8")

    # Assert with an independent JSON oracle and serialized text contract
    parsed = json.loads(raw)
    assert parsed == {"schema_version": 1, "items": [item]}
    assert type(parsed["schema_version"]) is int
    saved = parsed["items"][0]
    assert type(saved["quantity"]) is int
    assert type(saved["unit_price"]) is float
    assert type(saved["in_stock"]) is bool
    assert "Café Cards" in raw
    assert "\\u00e9" not in raw
    assert raw.endswith("\n")
    assert not raw.endswith("\n\n")

Das erwartete Dokument gehört zum Test. Es stammt weder aus dem Rückgabewert des Schreibers noch aus deinem eigenen JSON-Leser. Die ausdrücklichen Typprüfungen sind wichtig, weil Python Werte wie True und 1 sonst als gleich betrachtet. Wenn zwei Hilfsfunktionen im Anwendungscode denselben Fehler hätten, würde eine Prüfung der einen durch die andere falsche Sicherheit geben.

Führe die vollständige Testsuite aus:

python -m pytest -q

Diese Lektion muss rot enden. Die Testerkennung funktioniert weiterhin und die Auswahltests bestehen, aber der neue Test schlägt fehl, weil der vorgegebene Schreiber é als \\u00e9 maskiert. Lies den fehlgeschlagenen Testfall, die Assertion und den von pytest angezeigten tatsächlichen Wert. Bearbeite catalog.py noch nicht; die Reparatur gehört zu Lektion 5.

Prüfe, dass die Suite aus dem richtigen Grund rot ist. Du willst Status 1, wobei die Auswahltests weiterhin bestehen und dein neuer Test an seiner Unicode-Assertion scheitert. Das ist ein aussagekräftiges Rot: Die Suite wurde ausgeführt, hat gefunden, wonach sie gesucht hat, und widerspricht dem Anwendungscode.

Status 2 oder 5 wäre etwas anderes. Dann konnte pytest deine Tests nicht finden oder importieren, und du hast gar nichts über die Unicode-Vorgabe erfahren. Eine rote Testsuite liefert nur dann einen Beleg, wenn der Fehler genau die Frage betrifft, die du prüfen wolltest.

Eine Regel dabei: Kein Test darf in den Projektordner schreiben, auch wenn er danach aufräumt. Das Aufräumen wird nicht ausgeführt, wenn ein Test unterwegs scheitert. Gerade dann willst du keine Datei von gestern, die den morgigen Lauf durcheinanderbringt. Dafür ist tmp_path da.

Warum schreibst du Testausgaben unter tmp_path statt in das Projekt?

Warum vergleichst du mit einem im Test geschriebenen Dictionary, statt deinen eigenen JSON-Leser aufzurufen?

Aufgabe

Füge einen auffindbaren Test hinzu, der tmp_path anfordert, einen bisher nicht verwendeten Unicode-Artikel mit write_catalog_json schreibt, den tatsächlichen Text mit json aus der Standardbibliothek parst und sichtbares Unicode sowie genau einen abschließenden Zeilenumbruch prüft. Gib die Arbeit mit funktionierender Testerkennung und diesem relevanten Test ab, der am vorgegebenen Fehler mit maskiertem Unicode scheitert. Repariere den Anwendungscode in dieser Lektion noch nicht.