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 (Mocks)
# your_package/your_module.py
from pl_mocks_and_fakes import MockInUnitTests, MockReason
import random
@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()
# your_test_package/conftest.py
import pytest
from pl_mocks_and_fakes import initialize_mocks
import your_test_package
def pytest_runtest_setup(item: pytest.Item) -> None:
initialize_mocks(your_test_package)
# your_test_package/your_module_test.py
from pl_mocks_and_fakes import stub, mock_for
from your_package.your_module import random_int, random_int_and_string, random_string
def test_random_int_and_string() -> None:
# Use `stub` to set the return value of a mock for a specific test.
stub(random_int)(5)
# Use `mock_for` to get the Mock object.
mock_for(random_string).return_value = "foo"
result = random_int_and_string()
assert result == (5, "foo")
Usage (Fakes)
# your_package/jira_api_client.py
from dataclasses import dataclass
from pl_mocks_and_fakes import Fake, MockInUnitTests, THIRD_PARTY_API_MOCK_REASONS
@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(ticket.title)
# your_test_package/conftest.py
import pytest
from pl_mocks_and_fakes import create_fakes, initialize_mocks
import your_test_package
def pytest_runtest_setup(item: pytest.Item) -> None:
initialize_mocks(your_test_package)
create_fakes(your_test_package)
# your_test_package/jira_fake.py
from pl_mocks_and_fakes import Fake, mock_for
from your_package.jira_api_client 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
def create_jira_ticket(self, title: str) -> str:
return mock_for(create_jira_ticket).side_effect(title)
def fetch_jira_ticket(self, ticket_id: str) -> JiraTicket:
return mock_for(fetch_jira_ticket).side_effect(ticket_id)
# your_test_package/your_module_test.py
from pl_mocks_and_fakes import fake_for
from your_package.jira_api_client import duplicate_jira_ticket
from your_test_package.jira_fake import JiraFake
def test_duplicate_jira_ticket() -> None:
# Use `fake_for` to get the Fake object.
ticket_id = fake_for(JiraFake).create_jira_ticket("Ticket Name")
duplicated_ticket_id = duplicate_jira_ticket(ticket_id)
assert ticket_id != duplicated_ticket_id
assert fake_for(JiraFake).fetch_jira_ticket(duplicated_ticket_id).title == "Ticket Name"
assert len(fake_for(JiraFake).tickets) == 2
Releasing
Run ./release.sh.
License
Licensed under the Apache License 2.0. See LICENSE.
Metadata
Release files for pl-mocks-and-fakes 0.0.42
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pl_mocks_and_fakes-0.0.42.tar.gz | 9.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pl_mocks_and_fakes-0.0.42-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.4 kB
Release files / pl_mocks_and_fakes-0.0.42.tar.gz
| Download URL | pl_mocks_and_fakes-0.0.42.tar.gz |
|---|---|
| Size | 9.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
19d2cec35a2e0f11794085380614e5e4252441e8593072ab785a0761d8c05373
|
|
BLAKE2b-256 checksum How to use checksums |
6dc46ffcf9f0213b6b921ebd3584bf05b70d0c7fa958fdc335c3a5cce1ccdb86
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}
|
Release files / pl_mocks_and_fakes-0.0.42-py3-none-any.whl
| Download URL | pl_mocks_and_fakes-0.0.42-py3-none-any.whl |
|---|---|
| Size | 11.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e72b6dd843321b3dc3bcae8131a5392e9bf601f546ac36b3097c66ce19bde2a5
|
|
BLAKE2b-256 checksum How to use checksums |
41e6860d72cecb434d6dd7f1646f6057433b39d1790f960db682715947c4981a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}
|