A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby
—
Essential factory classes that form the foundation of Factory Boy's object generation capabilities. These classes support different build strategies and provide the base functionality for creating test objects.
The primary factory class supporting build, create, and stub strategies with batch operations and sequence management.
class Factory:
"""
Base factory class for creating objects with customizable attributes.
Meta attributes:
- model: The class to instantiate
- strategy: Default strategy ('build', 'create', 'stub')
- abstract: Set to True for abstract factories
"""
def build(**kwargs):
"""
Build instance without persistence.
Args:
**kwargs: Override default attribute values
Returns:
Instance of Meta.model
"""
def create(**kwargs):
"""
Create and persist instance (calls _create method).
Args:
**kwargs: Override default attribute values
Returns:
Persisted instance of Meta.model
"""
def stub(**kwargs):
"""
Create stub object with attributes only (no persistence).
Args:
**kwargs: Override default attribute values
Returns:
StubObject with specified attributes
"""
def build_batch(size, **kwargs):
"""
Build multiple instances without persistence.
Args:
size (int): Number of instances to create
**kwargs: Override default attribute values for all instances
Returns:
List of instances
"""
def create_batch(size, **kwargs):
"""
Create and persist multiple instances.
Args:
size (int): Number of instances to create
**kwargs: Override default attribute values for all instances
Returns:
List of persisted instances
"""
def stub_batch(size, **kwargs):
"""
Create multiple stub objects.
Args:
size (int): Number of stubs to create
**kwargs: Override default attribute values for all stubs
Returns:
List of StubObjects
"""
def generate(strategy, **kwargs):
"""
Generate instance using specified strategy.
Args:
strategy (str): 'build', 'create', or 'stub'
**kwargs: Override default attribute values
Returns:
Instance created with specified strategy
"""
def generate_batch(strategy, size, **kwargs):
"""
Generate multiple instances using specified strategy.
Args:
strategy (str): 'build', 'create', or 'stub'
size (int): Number of instances to create
**kwargs: Override default attribute values
Returns:
List of instances created with specified strategy
"""
def simple_generate(create, **kwargs):
"""
Generate instance with boolean create flag.
Args:
create (bool): True for create strategy, False for build
**kwargs: Override default attribute values
Returns:
Instance created with specified strategy
"""
def simple_generate_batch(create, size, **kwargs):
"""
Generate multiple instances with boolean create flag.
Args:
create (bool): True for create strategy, False for build
size (int): Number of instances to create
**kwargs: Override default attribute values
Returns:
List of instances
"""
def reset_sequence(value=None, force=False):
"""
Reset sequence counter for this factory.
Args:
value (int, optional): Value to reset to (default: 0)
force (bool): Force reset even if not at sequence start
"""
def attributes(create=False, extra=None):
"""
Build attribute dictionary without creating object instance.
(Deprecated - use build() or create() instead)
Args:
create (bool): Whether to use create strategy for attribute resolution
extra (dict, optional): Additional attributes to merge
Returns:
dict: Resolved attributes dictionary
"""
# Customization hooks
def _build(model_class, *args, **kwargs):
"""Override to customize object building."""
def _create(model_class, *args, **kwargs):
"""Override to customize object creation/persistence."""
def _after_postgeneration(instance, create, results):
"""Hook called after post-generation declarations."""# Basic factory definition
class UserFactory(Factory):
class Meta:
model = User
strategy = BUILD_STRATEGY # Optional, defaults to CREATE_STRATEGY
name = 'Test User'
email = Sequence(lambda n: f'user{n}@example.com')
# Using different strategies
user1 = UserFactory() # Uses default strategy (create)
user2 = UserFactory.build() # Build without persistence
user3 = UserFactory.create() # Create with persistence
user4 = UserFactory.stub() # Create stub object
# Batch operations
users = UserFactory.build_batch(5)
active_users = UserFactory.create_batch(3, is_active=True)
# Custom strategy
user = UserFactory.generate('stub', name='Custom User')Factory class for creating Python dictionaries with declared attributes.
class BaseDictFactory(Factory):
"""
Abstract base factory for dictionary-like classes.
Meta attributes:
- abstract: Always True for this base class
"""
class DictFactory(BaseDictFactory):
"""
Concrete factory for creating Python dictionaries.
Meta attributes:
- model: dict
"""class ConfigFactory(DictFactory):
api_key = Faker('uuid4')
timeout = 30
enabled = True
settings = Dict({
'debug': False,
'max_retries': Sequence(lambda n: n + 1)
})
config = ConfigFactory()
# Returns: {'api_key': '...', 'timeout': 30, 'enabled': True, 'settings': {...}}Factory class for creating Python lists with declared elements.
class BaseListFactory(Factory):
"""
Abstract base factory for list-like classes.
Meta attributes:
- abstract: Always True for this base class
"""
class ListFactory(BaseListFactory):
"""
Concrete factory for creating Python lists.
Meta attributes:
- model: list
"""class TagListFactory(ListFactory):
tag1 = Faker('word')
tag2 = Faker('word')
tag3 = 'default-tag'
tags = TagListFactory()
# Returns: ['random-word1', 'random-word2', 'default-tag']Factory class that only supports stub strategy, useful for creating test objects without any persistence.
class StubFactory(Factory):
"""
Factory that only supports stub strategy.
Meta attributes:
- strategy: STUB_STRATEGY
- model: StubObject
"""
def create(**kwargs):
"""Raises UnsupportedStrategy - not available for stub factories."""
class StubObject:
"""
Generic container for attribute storage.
Args:
**kwargs: Attributes to set on the object
"""
def __init__(self, **kwargs): ...class TestDataFactory(StubFactory):
name = 'Test Object'
value = Sequence(lambda n: n * 10)
metadata = Dict({'created': True})
# Only stub() works
obj = TestDataFactory.stub()
# obj.name == 'Test Object', obj.value == 0, etc.
# This raises UnsupportedStrategy
TestDataFactory.create() # Error!Decorator function to override the default strategy for a factory class.
def use_strategy(new_strategy):
"""
Decorator to force different strategy on factory class.
Args:
new_strategy (str): Strategy to use ('build', 'create', 'stub')
Returns:
Decorator function that modifies factory's default strategy
"""@use_strategy(BUILD_STRATEGY)
class AlwaysBuildUserFactory(Factory):
class Meta:
model = User
name = 'Build User'
# Even calling create() will use build strategy
user = AlwaysBuildUserFactory.create() # Actually builds, doesn't persistclass SimpleFactory(Factory):
class Meta:
model = MyModel
field1 = 'static value'
field2 = Sequence(lambda n: f'value_{n}')class BaseFactory(Factory):
class Meta:
model = BaseModel
abstract = True
created_at = LazyFunction(datetime.now)
is_active = True
class ConcreteFactory(BaseFactory):
class Meta:
model = ConcreteModel
name = Faker('name')class CustomFactory(Factory):
class Meta:
model = MyModel
name = 'Test'
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Custom creation logic."""
instance = super()._create(model_class, *args, **kwargs)
instance.custom_setup()
return instance
@classmethod
def _after_postgeneration(cls, instance, create, results):
"""Hook after post-generation."""
if create:
instance.finalize()Install with Tessl CLI
npx tessl i tessl/pypi-factory-boy