Testing a Real Project · practice
Isolate File Behavior
Selection tests have no lasting effects. A JSON writer does, so a useful test must choose where those bytes may exist. A fixed selected.json in the project would make tests depend on old state and leave artifacts behind.
Pytest supplies a fresh Path named tmp_path to each test that requests it. Add this file-behavior test:
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")
The expected document belongs to the test. It does not come from the writer’s True and 1 equal. If two production helpers shared the same bug, asking one to certify the other would be false confidence.
Run the complete suite:
python -m pytest -q
This lesson must end red. Collection remains healthy and the selection tests pass, but the new test fails because the seeded writer escapes é as \\u00e9. Read the failing node, the assertion, and pytest’s actual catalog.py yet; Lesson 5 owns that repair.
Check that you are red for the right reason. You want status 1, with the selection tests still passing and your new test failing on its Unicode assertion. That is a healthy red: the suite ran, found what it was looking for, and disagreed with production.
Status 2 or 5 would be a different story. Those mean pytest could not collect or import your tests, so nothing was learned about the Unicode contract at all. A red suite is only evidence when the failure is the one you were asking about.
One rule while you are here: no test may write into the project folder, even if it tidies up afterwards. Cleanup does not run when a test fails partway, which is exactly when you least want yesterday’s file confusing tomorrow’s run. That is what tmp_path is for.
Why write test output under tmp_path rather than into the project?
Why compare against a dictionary written in the test instead of calling your own JSON reader?
Task
Add a collected test that requests tmp_path, writes one unseen Unicode item through write_catalog_json, parses the real text with stdlib json, and checks visible Unicode plus exactly one trailing newline. Submit with healthy collection and that relevant test failing on the seeded escaped-Unicode defect; do not repair production in this lesson.