Skip to main content

⚒️ 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

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.16.0.tar.gz (95.5 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.16.0-py3-none-any.whl (156.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: object_mother_pattern-3.16.0.tar.gz
  • Upload date:
  • Size: 95.5 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.16.0.tar.gz
Algorithm Hash digest
SHA256 3fb98f1554a03a055e4da8d282ee123fb456f29d97bb8033d8d6542f111d4750
MD5 32862749cf24ed74d969ac3f302a588f
BLAKE2b-256 7cd127e3769e3660eb0aa853ed5675912ef57ac6be98113c08a5eb650bae2cd5

See more details on using hashes here.

Provenance

The following attestation bundles were made for object_mother_pattern-3.16.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.16.0-py3-none-any.whl.

File metadata

File hashes

Hashes for object_mother_pattern-3.16.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f376afe6ed3591d5337e24699732926f01f295c9b62831708e464653f0ccd05
MD5 55b17b51aa92f43636c3279da4fb3134
BLAKE2b-256 b138c90eda1e0f141a70f4410b4a20f33f27897ae2a6d6373b5bf1be3a196652

See more details on using hashes here.

Provenance

The following attestation bundles were made for object_mother_pattern-3.16.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.

Release history Release notifications | RSS feed

This release

3.16.0 This release

2 files

3.15.0

2 files

3.14.0

2 files

3.13.1

2 files

3.13.0

2 files

3.12.0

2 files

3.11.0

2 files

3.10.0

2 files

3.9.0

2 files

3.8.0

2 files

3.7.0

2 files

3.6.0

2 files

3.5.1

2 files

3.5.0

2 files

3.4.1

2 files

3.4.0

2 files

3.3.1

2 files

3.3.0

2 files

3.2.0

2 files

3.1.1

2 files

3.1.0

2 files

3.0.0

2 files

2.1.1

2 files

2.1.0

2 files

2.0.0

2 files

1.1.0

2 files

1.0.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

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