How to Snapshot Test JSON with Mock in Python
Use pytest-snapshot to capture the exact output of a JSON-loading function, with and without mocking json.loads, so future changes are automatically detected.
pip install pytest pytest-snapshot
Python code
31 linesimport json
from unittest.mock import Mock, patch
import pytest
def load_config(data):
config = json.loads(data)
return {"host": config["host"], "port": config["port"]}
def test_load_config_snapshot(snapshot):
mock_data = json.dumps({"host": "localhost", "port": 8080, "extra": "ignored"})
result = load_config(mock_data)
snapshot.assert_match(result)
def test_load_config_with_mocked_json(snapshot):
with patch("json.loads") as mock_loads:
mock_loads.return_value = {"host": "example.com", "port": 443, "debug": True}
result = load_config('{"irrelevant": true}')
snapshot.assert_match(result)
if __name__ == "__main__":
result1 = load_config(json.dumps({"host": "localhost", "port": 8080, "extra": "ignored"}))
print("First result:", json.dumps(result1))
with patch("json.loads") as mock_loads:
mock_loads.return_value = {"host": "example.com", "port": 443, "debug": True}
result2 = load_config('{"irrelevant": true}')
print("Second result:", json.dumps(result2))
Output
First result: {"host": "localhost", "port": 8080}
Second result: {"host": "example.com", "port": 443}
How it works
The snapshot fixture from pytest-snapshot stores the result of snapshot.assert_match(result) in a .snap file on the first run. On later runs, it compares the current result to the stored value, failing the test if anything differs. patch("json.loads") replaces the standard library function with a mock, letting you control exactly what load_config receives without relying on real JSON parsing. The load_config function itself only reads the host and port keys, so extra fields in the JSON are ignored — this is why both snapshots only contain those two keys. Using snapshots here means you get a clear diff when the function's behavior changes, catching regressions early.
Common mistakes
- Forgetting to install pytest-snapshot, which causes an `ImportError` for the `snapshot` fixture.
- Mocking `json.loads` but not the function that imports it — if you patch `json.loads` inside a module that uses `from json import loads`, the patch won't apply.
- Not considering that snapshot files must be committed to the repo for CI to have a baseline to compare against.
Variations
- Use `pytest-snapshot`'s `snapshot.snapshot_dir` to customize where snapshot files are stored.
- Instead of patching `json.loads`, you could pass a pre-parsed dict to a refactored function and snapshot the result directly.
Real-world use cases
- Regression testing a configuration parser that loads JSON from a file, ensuring output stays stable across refactors.
- Verifying that a service's response-processing function doesn't change its mapped fields when upstream JSON gains new keys.
- Locking down the output of a data transform in an ETL job so silent schema drifts are caught in CI.
Sponsored
More from Testing & modern typing
- Capture stdout and stderr with pytest capsys easy
- Characterization Test for Legacy Python Code medium
- Dataclass with Type Hints Fields in Python easy
- Dependency Injection in Python for Testability easy
- Design Data Helpers with Python TypedDict and Literal easy
- Fix and Test a Regression Bug in Python with Unit Tests easy
Keep learning
Related tutorials and quizzes for this topic.