The Object Mother Pattern is a Python package that simplifies and standardizes the creation of test objects.
Project description
⚒️ Object Mother Pattern
The Object Mother Pattern is a Python 🐍 package that simplifies and standardizes the creation of test 🧪 data.
Instead of hand-writing random values, invalid values, range boundaries, dates, identifiers, URLs, credit cards, and
other fixtures in every test module, you use reusable object mother classes with consistent validation behavior.
Table of Contents
- 📥 Installation
- 📚 Documentation
- ⚡ Quick Start
- 🧩 Core Ideas
- 🤔 Why Object Mothers?
- 📃 Available Mothers
- 🧪 Testing Patterns
- 🎄 Real-Life Case: Christmas Detector Service
- 🧑🔧 Creating Your Own Object Mother
- 🤝 Contributing
- 🔑 License
📥 Installation
You can install Object Mother Pattern using pip:
pip install object-mother-pattern
📚 Documentation
The root README is the entry point. Deeper guides live in this repository and are linked here:
docs/README.md: Documentation hub.docs/usage/README.md: Core usage, imports, validation, and custom mothers.docs/catalog/README.md: Feature map by mother category.- Catalog details:
primitives,dates,identifiers,internet,money, andpeople/text. docs/testing/README.md: Testing patterns for valid, invalid, boundary, and deterministic data.
This project's DeepWiki documentation is also available for generated repository navigation.
⚡ Quick Start
Use mothers directly in tests when you need valid values:
from object_mother_pattern import (
BooleanMother,
DateMother,
FloatMother,
IntegerMother,
StringMother,
)
from object_mother_pattern.mothers.identifiers.uuid import UuidV4Mother
integer = IntegerMother.create(min=-4, max=15)
amount = FloatMother.create(min=0, max=100, decimals=2)
enabled = BooleanMother.create()
username = StringMother.lowercase(min_length=8, max_length=16)
date = DateMother.create()
uuid = UuidV4Mother.create()
Pass an explicit value when a test needs a known valid value and you still want the mother to validate it:
from object_mother_pattern import IntegerMother
assert IntegerMother.create(value=7) == 7
Generate values outside an accepted range when testing validation failures:
from datetime import date
from object_mother_pattern import DateMother
value = DateMother.out_of_range(
start_date=date(year=2025, month=1, day=1),
end_date=date(year=2025, month=1, day=31),
)
🧩 Core Ideas
Most mothers follow the same pattern:
create(value=...)validates and returns an explicit value.create(...)withoutvaluegenerates a valid random value.- Dedicated helpers such as
empty(),of_length(),positive(),odd(), orout_of_range()express common test shapes. invalid_type()generates a value with the wrong type for negative-path tests.- Collection mothers can compose other mothers with callables such as
item_mother,key_mother, andvalue_mother.
from object_mother_pattern.models import DictMother, ListMother
from object_mother_pattern import IntegerMother, StringMother
values = ListMother.of_length(length=3, item_mother=IntegerMother.positive)
payload = DictMother.of_length(
length=2,
key_mother=lambda: StringMother.lowercase(min_length=4, max_length=8),
value_mother=IntegerMother.create,
)
🤔 Why Object Mothers?
Object mothers help tests say what kind of value they need instead of repeating how that value is built. A hardcoded
literal such as 'john@example.com', '550e8400-e29b-41d4-a716-446655440000', or 42 can be perfectly valid, but when
every test invents its own literals the setup becomes duplicated, inconsistent, and harder to update when a validation
rule changes.
Use object mothers when the exact value does not matter and the test only needs a value that satisfies a shape:
from object_mother_pattern import IntegerMother
from object_mother_pattern.mothers.internet import EmailAddressMother
email = EmailAddressMother.create()
quantity = IntegerMother.positive()
assert '@' in email
assert quantity > 0
This keeps the test focused on the behavior under test. The mother owns the details of valid email generation, positive integer generation, invalid types, ranges, and special formats. If those rules evolve, tests that only need "a valid email" or "a positive integer" do not need to be rewritten.
Hardcoded values are still the best choice when the value is the point of the test:
- Use fixed literals for exact serialization, snapshots, URLs, JSON, SQL, error messages, and UI copy.
- Use explicit boundary values for deliberate limits such as minimum length, maximum length, zero, one, empty strings, first date, last date, or a known invalid format.
- Use a known literal when reproducing a specific bug.
- Use
create(value=...)when you want an explicit value but still want the mother to validate that it belongs to the expected shape.
from object_mother_pattern import IntegerMother, StringMother
assert StringMother.create(value='invoice-paid') == 'invoice-paid'
assert IntegerMother.create(value=10) == 10
The practical rule is simple: generate values for invariant-based tests, hardcode values for exact examples and intentional limits.
📃 Available Mothers
The package includes mothers for:
| Category | Examples |
|---|---|
| Models | BaseMother, EnumerationMother, ListMother, DictMother |
| Primitives | BooleanMother, BytesMother, FloatMother, IntegerMother, StringMother |
| Dates | DateMother, DatetimeMother, StringDateMother, StringDatetimeMother, timezone mothers |
| Identifiers | UUID mothers, Spanish identifiers, world/country code identifiers |
| Internet | URLs, domains, hosts, ports, IP addresses, networks, MAC addresses, email addresses, user agents |
| Money | IBANs, credit cards by brand, Bitcoin wallet values |
| People | Full names, usernames, passwords |
| Extra | Text snippets |
See docs/catalog/README.md for a deeper feature map and import guidance.
🧪 Testing Patterns
Use explicit values when an assertion depends on exact output:
from object_mother_pattern import StringMother
assert StringMother.create(value='known-value') == 'known-value'
Use generated values when the test only cares about invariants:
from object_mother_pattern import IntegerMother
value = IntegerMother.positive()
assert value > 0
Use invalid helpers for negative-path coverage:
from pytest import raises
from object_mother_pattern import IntegerMother
with raises(TypeError):
IntegerMother.create(value=IntegerMother.invalid_type())
More guidance is available in docs/testing/README.md.
🎄 Real-Life Case: Christmas Detector Service
This service checks whether a date falls within a Christmas holiday range. Tests use
DateMother
to create dates inside and outside the accepted range without duplicating date-generation logic.
from datetime import date
from object_mother_pattern import DateMother
class ChristmasDetectorService:
def __init__(self) -> None:
self._christmas_start = date(year=2024, month=12, day=24)
self._christmas_end = date(year=2025, month=1, day=6)
def is_christmas(self, today: date) -> bool:
return self._christmas_start <= today <= self._christmas_end
christmas_detector_service = ChristmasDetectorService()
def test_christmas_detector_is_christmas() -> None:
today = DateMother.create(
start_date=date(year=2024, month=12, day=25),
end_date=date(year=2025, month=1, day=6),
)
assert christmas_detector_service.is_christmas(today=today)
def test_christmas_detector_is_not_christmas() -> None:
today = DateMother.out_of_range(
start_date=date(year=2024, month=12, day=24),
end_date=date(year=2025, month=1, day=6),
)
assert christmas_detector_service.is_christmas(today=today) is False
🧑🔧 Creating Your Own Object Mother
You can extend the functionality of this library by subclassing the
BaseMother
class. A custom mother should validate explicit values and generate valid values when no value is provided.
from random import randint
from object_mother_pattern.models import BaseMother
class PositiveIntegerMother(BaseMother[int]):
@classmethod
def create(cls, *, value: int | None = None) -> int:
if value is not None:
if type(value) is not int:
raise TypeError('PositiveIntegerMother value must be an integer.')
if value <= 0:
raise ValueError('PositiveIntegerMother value must be positive.')
return value
return randint(a=1, b=100)
More detail is available in docs/usage/README.md.
🤝 Contributing
We love community help! Before you open an issue or pull request, please read:
Thank you for helping make ⚒️ Object Mother Pattern package awesome! 🌟
🔑 License
This project is licensed under the terms of the MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file object_mother_pattern-3.13.1.tar.gz.
File metadata
- Download URL: object_mother_pattern-3.13.1.tar.gz
- Upload date:
- Size: 94.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed0508b68c1477a1b894c97755a45daa5325b835f5153edf0ed5998da7a31582
|
|
| MD5 |
be8e1380fe82821ffb3e22adfd6147b5
|
|
| BLAKE2b-256 |
94b2558219307bad310bfac54401779808cbe6f8737d10706b69725711729716
|
Provenance
The following attestation bundles were made for object_mother_pattern-3.13.1.tar.gz:
Publisher:
ci.yaml on adriamontoto/object-mother-pattern
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
object_mother_pattern-3.13.1.tar.gz -
Subject digest:
ed0508b68c1477a1b894c97755a45daa5325b835f5153edf0ed5998da7a31582 - Sigstore transparency entry: 1852349333
- Sigstore integration time:
-
Permalink:
adriamontoto/object-mother-pattern@3f39c5ae6a9cdd6b2021e166cceb32aa0bccb2df -
Branch / Tag:
refs/heads/master - Owner: https://github.com/adriamontoto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@3f39c5ae6a9cdd6b2021e166cceb32aa0bccb2df -
Trigger Event:
push
-
Statement type:
File details
Details for the file object_mother_pattern-3.13.1-py3-none-any.whl.
File metadata
- Download URL: object_mother_pattern-3.13.1-py3-none-any.whl
- Upload date:
- Size: 155.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3ec281e68f55270c086db2ab63ebf7e8592b6d3e2a9e6bcedfc82dc231fa333
|
|
| MD5 |
e423411f221a489a495b898321f4f4ec
|
|
| BLAKE2b-256 |
5b1036b3c5efd4f82b37796c67141cf1e8628be2113008adce62d55f53381b06
|
Provenance
The following attestation bundles were made for object_mother_pattern-3.13.1-py3-none-any.whl:
Publisher:
ci.yaml on adriamontoto/object-mother-pattern
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
object_mother_pattern-3.13.1-py3-none-any.whl -
Subject digest:
f3ec281e68f55270c086db2ab63ebf7e8592b6d3e2a9e6bcedfc82dc231fa333 - Sigstore transparency entry: 1852349505
- Sigstore integration time:
-
Permalink:
adriamontoto/object-mother-pattern@3f39c5ae6a9cdd6b2021e166cceb32aa0bccb2df -
Branch / Tag:
refs/heads/master - Owner: https://github.com/adriamontoto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@3f39c5ae6a9cdd6b2021e166cceb32aa0bccb2df -
Trigger Event:
push
-
Statement type: