Pytest fixtures

Updated Jul 14, 2026

simulacat registers a pytest plugin that provides fixtures for configuring and running the GitHub API simulator. The lowest-level fixture is github_sim_config.

Scenario fixtures

simulacat also provides higher-level fixtures that return ready-to-use configuration mappings derived from the scenario factories:

  • simulacat_single_repo (single repository owned by octocat)
  • simulacat_empty_org (empty organization named octo-org)

Use these fixtures to override github_sim_config or to compose additional configuration layers:

import pytest


@pytest.fixture
def github_sim_config(simulacat_single_repo):
    return simulacat_single_repo

github_sim_config

github_sim_config returns a JSON-serializable mapping describing the initial simulator state. By default, it is an empty dictionary ({}); the orchestration layer expands an empty config into the minimal valid state when starting the simulator.

Override the fixture at different scopes using standard pytest rules:

  • Function scope via indirect parametrization:
import pytest


@pytest.mark.parametrize(
    "github_sim_config",
    [{"users": [{"login": "alice", "organizations": []}]}],
    indirect=True,
)
def test_uses_parametrized_config(github_sim_config):
    assert github_sim_config["users"][0]["login"] == "alice"
  • Module scope by defining a fixture in a test module:
import pytest


@pytest.fixture
def github_sim_config():
    return {"users": [{"login": "alice", "organizations": []}]}


def test_uses_module_override(github_sim_config):
    assert github_sim_config["users"][0]["login"] == "alice"
  • Package scope by defining a fixture in conftest.py:
# tests/conftest.py
import pytest


@pytest.fixture(scope="package")
def github_sim_config():
    return {"users": [{"login": "alice", "organizations": []}]}

github_simulator

github_simulator starts the Bun-based GitHub API simulator using the current github_sim_config, then yields a github3.GitHub client configured to send requests to the local simulator.

def test_rate_limit(github_simulator):
    payload = github_simulator.rate_limit()
    assert payload["rate"]["limit"] > 0

The simulator process is stopped after the test, even if the test fails.

simulacat patches simulator responses for common github3.py calls (repository lookup and listing, issue retrieval, and pull request retrieval) so that rich model objects can be constructed when the client sends the application/vnd.github.v3.full+json accept header.

Other github3.py methods may still raise github3.exceptions.IncompleteResponse if the simulator response is missing fields that the client library expects. In those cases, prefer endpoints like rate_limit() or use github_simulator.session to make raw HTTP requests.