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

🔼 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.13.1.tar.gz (94.4 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.13.1-py3-none-any.whl (155.5 kB view details)

Uploaded Python 3

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

Hashes for object_mother_pattern-3.13.1.tar.gz
Algorithm Hash digest
SHA256 ed0508b68c1477a1b894c97755a45daa5325b835f5153edf0ed5998da7a31582
MD5 be8e1380fe82821ffb3e22adfd6147b5
BLAKE2b-256 94b2558219307bad310bfac54401779808cbe6f8737d10706b69725711729716

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for object_mother_pattern-3.13.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f3ec281e68f55270c086db2ab63ebf7e8592b6d3e2a9e6bcedfc82dc231fa333
MD5 e423411f221a489a495b898321f4f4ec
BLAKE2b-256 5b1036b3c5efd4f82b37796c67141cf1e8628be2113008adce62d55f53381b06

See more details on using hashes here.

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

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