Why your mock breaks later

Mocking gone wild: tests pass today, explode tomorrow—and the comments are on fire

TLDR: Global mocking broke a test coverage tool, so the author saved a clean “open” and urged patching where code uses things. Commenters clashed: some say mocking is brittle and should be replaced with better design or containers; others want tools to ignore patches during tests. Why it matters: fewer surprise test failures.

A blog warned that faking stuff the wrong way makes tests explode later, and wow did the community show up with pitchforks and punchlines. The culprit: developers mocked the computer’s “open the file” command globally, so a test tool called coverage.py accidentally used the fake version and fell on its face. The fix? Patch where the thing is used, not where it’s defined—and the coverage author even stashed a safe, original “open” to dodge future chaos, especially with Python 3.14 making this more common.

Cue the drama. gsnedders says the real villain is when patches get applied and unapplied, arguing the test tool should avoid test-time monkey business. esafak waved the “just use containers” flag: run real mini-services instead of pretending. Izkata reminded everyone this “mock where used” rule is a Python quirk, not a universal truth. kaashif went designer: why mock at all—just pass the data in! And lelandbatey dropped the nuke: mocking is brittle and bad, breaking whenever code changes.

Jokes flew fast: “open season on open,” “Schrödinger’s test—passing and detonating later,” and “coverage vs. courage.” The thread split between mock less, design better and tools should be patch-proof, with the blog author landing the pragmatic middle: fix it now, reduce pain later.

Key Points

  • Mocking builtins.open globally can make tests pass initially but cause later failures during test execution.
  • Coverage.py may read source files during tests and can break if open is globally mocked, triggering type errors.
  • Correct practice is to patch where the object is used (e.g., module-level open) rather than where it’s defined.
  • Coverage.py implements a defensive fix by caching the original builtin open at import time to avoid interference.
  • The issue currently manifests in coverage.py with Python 3.14 and may occur more as adoption of 3.14 grows.

Hottest takes

"Arguably this is a problem in when the patch is unapplied." — gsnedders
"Why even mock anything in this example?" — kaashif
"Which highlights how awful mocking as a concept is; it is of truly limited usefulness for anything but the most brittle of tests." — lelandbatey
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.