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.

Medium Python 3.9+ Aug 9, 2026 Testing & modern typing 14 views 0 copies

Requires third-party packages — install first
pip install pytest pytest-snapshot

Python code

31 lines
Python 3.9+
import 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

stdout
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

  1. Use `pytest-snapshot`'s `snapshot.snapshot_dir` to customize where snapshot files are stored.
  2. 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

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Testing & modern typing

Related tutorials and quizzes for this topic.