Module 6: Testing, Debugging, and Safe Boundaries

Testing Behavior with pytest

Testing Behavior with pytest

Tests make expected behavior repeatable. Focused unit tests give fast feedback, integration tests verify boundaries, and a few end-to-end tests cover the real user path.

Module: Module 6: Testing, Debugging, and Safe Boundaries

Core mental model

This lesson is built around four connected ideas. Read them as a decision framework, then prove each one with the walkthrough.

  • Tests should assert public behavior rather than private implementation steps.
  • Parametrization runs one rule against multiple examples.
  • tmp_path keeps file tests isolated and portable.
  • Mocks are most useful at slow, unsafe, or nondeterministic external boundaries.

Walkthrough

import pytest
from logreport.parser import parse_line

@pytest.mark.parametrize(
    ("raw", "expected"),
    [
        ("info|ready", ("INFO", "ready")),
        (" ERROR | timeout ", ("ERROR", "timeout")),
    ],
)
def test_parse_line(raw, expected):
    assert parse_line(raw) == expected

def test_parse_line_rejects_missing_separator():
    with pytest.raises(ValueError):
        parse_line("broken")

The test names identify behavior. Parametrization removes duplicate structure, and the failure case defines malformed shape as part of the parser contract.

Hands-on lab

Create tests for parsing, validation, aggregation, formatting, and file IO. Include empty files, Unicode, unknown levels, and malformed records.

What to watch for

  • One huge end-to-end test makes failures hard to localize.
  • Over-mocking may test only the mock setup.
  • Tests depending on time, order, or global state become flaky.

Engineering checklist

  • Connect the lesson's mental model to the choices made in the walkthrough.
  • Test the normal case, an empty or boundary case, and one invalid case.
  • Keep external input, side effects, and reusable logic in clearly separated layers.
  • Prefer the clearest correct implementation before optimizing or generalizing it.

Completion check

You can implement the lab without copying the example, explain the core concepts in your own words, and show tests or terminal output that demonstrate the expected and failure paths.