Skip to main content

Mock slow, nondeterministic, and side-effect-producing code with minimal per-test configuration.

Project description

pl-mocks-and-fakes

Mock slow, nondeterministic, and side-effect-producing code with minimal per-test configuration.

Project Status

Alpha. Expect breaking changes.

Installation

uv add pl-mocks-and-fakes

Usage

from dataclasses import dataclass

from pl_mocks_and_fakes import Fake, MockInUnitTests, MockReason, THIRD_PARTY_API_MOCK_REASONS
import random

# Production code in your_package/your_module.py

@MockInUnitTests(MockReason.NONDETERMINISTIC)
def random_int() -> int:
    return random.randint(0, 100)

@MockInUnitTests(MockReason.NONDETERMINISTIC)
def random_string() -> str:
    return random.choice(["foo", "bar", "baz"])

def random_int_and_string() -> tuple[int, str]:
    return random_int(), random_string()


@dataclass
class JiraTicket:
    id: str
    title: str


@MockInUnitTests(*THIRD_PARTY_API_MOCK_REASONS)
def create_jira_ticket(title: str) -> str:
    # This makes a third-party API call.
    # ...
    pass

@MockInUnitTests(*THIRD_PARTY_API_MOCK_REASONS)
def fetch_jira_ticket(ticket_id: str) -> JiraTicket:
    # This makes a third-party API call.
    # ...
    pass

def duplicate_jira_ticket(ticket_id: str) -> str:
    ticket = fetch_jira_ticket(ticket_id)
    return create_jira_ticket(title=ticket.title)


# conftest.py in your_test_package/conftest.py

import pytest
from pl_mocks_and_fakes import initialize_mocks, create_fakes
import your_package
import your_test_package

def pytest_runtest_setup(item: pytest.Item) -> None:
    if not any(marker.name == "integration" for marker in item.iter_markers()):
        initialize_mocks(your_package)
        create_fakes(your_test_package)

# Fake code in your_test_package/jira_fake.py

from pl_mocks_and_fakes import Fake, mock_for
from your_package.your_module import JiraTicket, create_jira_ticket, fetch_jira_ticket

class JiraFake(Fake):
    def __init__(self):
        def _create_jira_ticket_side_effect(title: str) -> str:
            ticket_id = f"FAKE-{len(self.tickets) + 1}"
            self.tickets.append(JiraTicket(id=ticket_id, title=title))
            return ticket_id

        def _fetch_jira_ticket_side_effect(ticket_id: str) -> JiraTicket:
            for ticket in self.tickets:
                if ticket.id == ticket_id:
                    return ticket
            raise ValueError(f"Ticket with id {ticket_id} not found")

        self.tickets: list[JiraTicket] = []
        mock_for(create_jira_ticket).side_effect = _create_jira_ticket_side_effect
        mock_for(fetch_jira_ticket).side_effect = _fetch_jira_ticket_side_effect

# Test code in your_test_package/your_module_test.py

from pl_mocks_and_fakes import stub, mock_for, fake_for
from your_package.your_module import random_int, random_int_and_string, random_string, duplicate_jira_ticket, JiraTicket, create_jira_ticket, fetch_jira_ticket
from your_test_package.jira_fake import JiraFake

def test_random_int_and_string() -> None:
    stub(random_int)(5) # Use `stub` to set the return value of a mock for a specific test.
    mock_for(random_string).return_value = "foo" # Use `mock_for` to get the Mock object.

    result = random_int_and_string()

    assert result == (5, "foo")

def test_duplicate_jira_ticket() -> None:
    # Use mocked functions as if they were the real functions. The Fake will be used instead.
    ticket_id = create_jira_ticket("Ticket Name")

    duplicated_ticket_id = duplicate_jira_ticket(ticket_id)

    assert ticket_id != duplicated_ticket_id
    assert fetch_jira_ticket(duplicated_ticket_id).title == "Ticket Name"
    # Use `fake_for` to get the Fake object.
    assert len(fake_for(JiraFake).tickets) == 2

Releasing

Run ./release.sh.

License

Licensed under the Apache License 2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pl_mocks_and_fakes-0.0.4.tar.gz (9.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pl_mocks_and_fakes-0.0.4-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

File details

Details for the file pl_mocks_and_fakes-0.0.4.tar.gz.

File metadata

  • Download URL: pl_mocks_and_fakes-0.0.4.tar.gz
  • Upload date:
  • Size: 9.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pl_mocks_and_fakes-0.0.4.tar.gz
Algorithm Hash digest
SHA256 c7e970822963979622ad74715eb121b249b10b62fc0492b79196673d3a46685a
MD5 14d4bd31fca38efee27f2d8e44c8c06b
BLAKE2b-256 57f68722f094945af36112176d191bca159d6f0b5f27a14c982ae0aaec22a1c7

See more details on using hashes here.

File details

Details for the file pl_mocks_and_fakes-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: pl_mocks_and_fakes-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 12.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pl_mocks_and_fakes-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 6b555c68097e30f79cb6d020f2b76825e324231934941d11123aea8448ff8b02
MD5 558f0a5ae68b113b34a08a4de010f0a2
BLAKE2b-256 931d36db99e97fd1155b5d305d3805b82da701f0de85e9f981b45a3a39873a24

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page