Skip to main content

The Object Mother Pattern is a Python package that simplifies and standardizes the creation of test objects.

Project description

⚒️ Object Mother Pattern

CI Pipeline Coverage Pipeline Package Version Supported Python Versions Package Downloads Project Documentation

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

🔼 Back to top



📥 Installation

You can install Object Mother Pattern using pip:

pip install object-mother-pattern

You can install the companion AI-agent skill from skills.sh with Vercel's skills CLI:

npx skills add adriamontoto/object-mother-pattern

Review the skill source in skills/object-mother-pattern before installing it in sensitive environments.

🔼 Back to top



📚 Documentation

The root README is the entry point. Deeper guides live in this repository and are linked here:

This project's DeepWiki documentation is also available for generated repository navigation.

🔼 Back to top



⚡ 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),
)

🔼 Back to top



🧩 Core Ideas

Most mothers follow the same pattern:

  • create(value=...) validates and returns an explicit value.
  • create(...) without value generates a valid random value.
  • Dedicated helpers such as empty(), of_length(), positive(), odd(), or out_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, and value_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,
)

🔼 Back to top



🤔 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.

🔼 Back to top



📃 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.

🔼 Back to top



🧪 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.

🔼 Back to top



🎄 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

🔼 Back to top



🧑‍🔧 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.

🔼 Back to top



🤝 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! 🌟

🔼 Back to top



🔑 License

This project is licensed under the terms of the MIT license.

🔼 Back to top

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

object_mother_pattern-3.14.0.tar.gz (94.6 kB view details)

Uploaded Source

Built Distribution

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

object_mother_pattern-3.14.0-py3-none-any.whl (155.6 kB view details)

Uploaded Python 3

File details

Details for the file object_mother_pattern-3.14.0.tar.gz.

File metadata

  • Download URL: object_mother_pattern-3.14.0.tar.gz
  • Upload date:
  • Size: 94.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for object_mother_pattern-3.14.0.tar.gz
Algorithm Hash digest
SHA256 e2261500a7be06c047741cbbb92aedba4c1b79ab37e3b55d6b30c2d82142ec61
MD5 abd187cb7bf464848c3d1ce9ae733462
BLAKE2b-256 6089de9bc34e264b8eeb15e2bddecfc1a735408e8a0ff67a91a77a885114f72b

See more details on using hashes here.

Provenance

The following attestation bundles were made for object_mother_pattern-3.14.0.tar.gz:

Publisher: ci.yaml on adriamontoto/object-mother-pattern

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file object_mother_pattern-3.14.0-py3-none-any.whl.

File metadata

File hashes

Hashes for object_mother_pattern-3.14.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c76bcced04e5ea403af4fbe61f31e22ceae63514499a13cb509db5c9e124ce30
MD5 46a6c1373e27a55706cca13b4f964fb6
BLAKE2b-256 392e1ee9b24444bde16bb0aa555aa1334d17428208d2b72db5700fe5ed162267

See more details on using hashes here.

Provenance

The following attestation bundles were made for object_mother_pattern-3.14.0-py3-none-any.whl:

Publisher: ci.yaml on adriamontoto/object-mother-pattern

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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