Skip to main content

Command Mock Framework

PyPI version Tests

High-fidelity, deterministic command mocking for Python tests.

Stop mocking subprocess.run with invented strings. Record real command outputs once, store them in version control, and replay them during tests.


The Problem

Testing code that wraps CLI tools (Git, Docker, Kubectl, npm) is painful.

  • Manual mocks are brittle: You guess what git log returns, but you get it wrong.
  • Real commands are slow: Running docker ps in every test kills performance.
  • Integration tests are flaky: Environments change, causing non-deterministic failures.

The Solution

Command Mock Framework is a VCR-style library for subprocess.run. It sits between your code and subprocess.

  1. Record real command outputs to TOML files.
  2. Replay them instantly in tests.
  3. Match commands flexibly using template placeholders.

Easily mock complex tools like AWS CLI, Kubectl, Terraform, and Git without manually constructing stdout strings.

Quick Example

1. Record the real behavior:

from command_mock.recorder import CommandMockRecorder

# Run this once to generate 'mocks/git/log/follow.toml'
recorder = CommandMockRecorder("git")
recorder.record_scenario(
    command=["git", "log", "--follow", "--", "{filepath}"],
    scenario_name="basic_history",
    template_vars={"filepath": "app.py"}
)

2. Use it in your test:

def test_get_history(command_mock):
    # Load the mock (command_mock is a pytest fixture)
    mock_fn = command_mock.get_subprocess_mock("log/follow.toml", "basic_history")

    # Patch subprocess.run
    with patch('subprocess.run', side_effect=mock_fn):
        # This executes FAST and returns REAL git output
        # It matches 'git log ... -- app.py' OR 'git log ... -- other.py'
        history = my_git_wrapper.get_history("app.py")

    assert len(history) == 5

Alternatives & Philosophy

The Command Mock Framework occupies a specific niche: it applies the VCR/Record-Replay pattern (popularized by HTTP tools like vcrpy) to subprocess/CLI calls.

Stop using unittest.mock.patch with fake stdout strings. This framework guarantees fidelity by recording reality first.

Here is how it compares to other tools in the Python ecosystem:

1. The Direct Competitor: pytest-subprocess

This is the most popular modern library for this task. It allows you to define expected commands and outputs inside your test code.

  • pytest-subprocess: Best for Code-Driven testing. Excellent for defining logic flows (e.g., "if command X runs, return exit code 1").
  • command-mock: Best for Data-Driven testing. It separates test data (TOML) from test logic. It shines when output is verbose or structured (like git log or docker inspect) and you want to version-control the exact output snapshot.

2. The Standard Library: unittest.mock

The "vanilla" way that this framework was built to replace.

  • unittest.mock: Often leads to brittle tests. You have to manually invent stdout strings, which means your tests might pass while the real app fails because your invented string wasn't quite right.
  • command-mock: Guarantees fidelity by recording reality first.

3. "Real Execution" Tools (cram, scripttest)

These tools run actual shell commands in a sandbox.

  • cram: Provides 100% realism but is slow and requires a full environment setup (installing git, docker, etc. on the test runner).
  • command-mock: Replays instantly (⚡ Fast) and requires no external tools installed in the CI environment.

4. The HTTP Equivalent: vcrpy

If your CLI tool is primarily a wrapper around an API (e.g., a custom AWS wrapper), you might be mocking the wrong layer.

  • Strategy: Instead of mocking the subprocess call to aws-cli, use the Python SDK (boto3) and use vcrpy to record the HTTP interactions. Use command-mock when you must shell out to a binary.

Summary

Feature command-mock pytest-subprocess unittest.mock cram
Primary Goal High-fidelity Replay Programmatic Logic Basic Mocking Integration Testing
Data Storage External Files (TOML) In Python Code In Python Code Shell Transcript Files
Realism ⭐⭐⭐⭐ (Recorded) ⭐⭐ (Manual) ⭐ (Manual) ⭐⭐⭐⭐⭐ (Real)
Speed ⚡ Fast ⚡ Fast ⚡ Fast 🐢 Slow
Best For Complex outputs Logic flows, exit codes Simple commands End-to-end flows

Conclusion: If you need to mock complex tools like Git, Docker, or Kubectl where the stdout is verbose and structured, command-mock is the best fit because managing those massive strings inside Python code is messy and error-prone.


Installation

pip install orgecc-command-mock

Usage Guide

1. Setup

Add the pytest plugin to your conftest.py:

# tests/conftest.py
import pytest
from pathlib import Path
from command_mock.recorder import CommandMockRecorder
from command_mock.player import CommandMockPlayer

@pytest.fixture
def command_mock(request):
    """Fixture that switches between Player (default) and Recorder."""
    # Point this to where you want to store your TOML files
    fixtures_root = Path(__file__).parent

    if request.config.getoption("--regenerate-mocks"):
        return CommandMockRecorder("git", fixtures_root=fixtures_root)
    else:
        return CommandMockPlayer("git", fixtures_root=fixtures_root)

def pytest_addoption(parser):
    parser.addoption("--regenerate-mocks", action="store_true", help="Record new mocks")

2. Recording Mocks

Create a script (e.g., tests/generate_mocks.py) to generate your test data. This ensures your mocks are reproducible.

from command_mock.recorder import CommandMockRecorder

def generate():
    recorder = CommandMockRecorder("git")

    # You can even use setup scripts to create real repo states!
    repo = recorder.create_test_repo("scripts/setup_repo.sh")

    recorder.record_scenario(
        command=["git", "status"],
        scenario_name="clean_state",
        output_path="status/clean.toml",
        repo_path=repo
    )

if __name__ == "__main__":
    generate()

3. Flexible Matching

This is the framework's superpower. You don't need a mock for every single argument variation. Use placeholders in your templates.

Embedded Placeholders:

# Template in TOML:
command = ["git", "log", "--grep={term}"]

# Matches all of these in tests:
["git", "log", "--grep=fix"]
["git", "log", "--grep=feat"]

Standalone Placeholders:

# Template in TOML:
command = ["git", "add", "{filepath}"]

# Matches all of these in tests:
["git", "add", "src/main.py"]
["git", "add", "tests/test_core.py"]

Dynamic Flag Stripping: The player automatically handles flags that change every run (like --since="1 hour ago"), matching the core command while ignoring the dynamic parts.


Real-World Example: Hug SCM

This framework was extracted from Hug SCM, a humane Git interface. Hug SCM relies on this library to test its complex Git history analysis features without needing a Git repo in CI.

You can explore Hug SCM's source code to see the framework in action:

Component File in Hug SCM Purpose
Integration tests/conftest.py Shows how to configure the command_mock fixture to point to a local fixtures/ directory.
Recording tests/fixtures/generate_mocks.py A robust script that generates 50+ mocks for git log, churn, and activity analysis. Demonstrates batch recording.
Data tests/fixtures/mocks/git/log/ See how real TOML mock files are structured and organized by command.
Tests tests/test_activity.py See how tests consume these mocks to validate complex logic like "weekend work detection".

Development

This project uses a Makefile for all development tasks.

make install      # Install dev dependencies
make test         # Run tests
make format       # Format code (Black/Ruff)
make ci           # Run full CI suite locally

For detailed contribution guidelines, see CLAUDE.md.

License

Apache 2.0

Metadata

Release files for orgecc-command-mock 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for orgecc-command-mock 0.1.6
File Size Uploaded Provenance
orgecc_command_mock-0.1.6.tar.gz 30.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for orgecc-command-mock 0.1.6
File Interpreter ABI Platform
orgecc_command_mock-0.1.6-py3-none-any.whl Python 3 none any Details

Total release size: 44.6 kB

Release files / orgecc_command_mock-0.1.6.tar.gz

Download URL orgecc_command_mock-0.1.6.tar.gz
Size 30.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a6cc8f058f798a1f7bb1505c09ca4c0438916b66f948d746b51c33334ee8d902
BLAKE2b-256 checksum
How to use checksums
ddf3bec5e516b44f2fce4fde7b06fede106ea78726ad65da3a8747b0b46727c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 26, 2025.

Transparency log

Release files / orgecc_command_mock-0.1.6-py3-none-any.whl

Download URL orgecc_command_mock-0.1.6-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
655823d2d31c218549d272ec5f6c81c9e9473b1b2265a3927799b3c486bbdf53
BLAKE2b-256 checksum
How to use checksums
bc0bfec47c538618d38d5fd709a07f0cff4c5ef41d26f04e1b7128812e28fad1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 26, 2025.

Transparency log

Security for orgecc-command-mock 0.1.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for orgecc_command_mock-0.1.6.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 26, 2025.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page