Introduction

The purpose of factory_boy is to provide a default way of getting a new instance, while still being able to override some fields on a per-call basis.

Note

This section will drive you through an overview of factory_boy’s feature. New users are advised to spend a few minutes browsing through this list of useful helpers.

Users looking for quick helpers may take a look at Common recipes, while those needing detailed documentation will be interested in the Reference section.

Basic usage

Factories declare a set of attributes used to instantiate an object, whose class is defined in the class Meta’s model attribute:

  • Subclass factory.Factory (or a more suitable subclass)

  • Add a class Meta: block

  • Set its model attribute to the target class

  • Add defaults for keyword args to pass to the associated class’ __init__ method

import factory
from . import base

class UserFactory(factory.Factory):
    class Meta:
        model = base.User

    firstname = "John"
    lastname = "Doe"

You may now get base.User instances trivially:

>>> john = UserFactory()
<User: John Doe>

It is also possible to override the defined attributes by passing keyword arguments to the factory:

>>> jack = UserFactory(firstname="Jack")
<User: Jack Doe>

A given class may be associated to many Factory subclasses:

class EnglishUserFactory(factory.Factory):
    class Meta:
        model = base.User

    firstname = "John"
    lastname = "Doe"
    lang = 'en'


class FrenchUserFactory(factory.Factory):
    class Meta:
        model = base.User

    firstname = "Jean"
    lastname = "Dupont"
    lang = 'fr'
>>> EnglishUserFactory()
<User: John Doe (en)>
>>> FrenchUserFactory()
<User: Jean Dupont (fr)>

Sequences

When a field has a unique key, each object generated by the factory should have a different value for that field. This is achieved with the Sequence declaration:

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    username = factory.Sequence(lambda n: 'user%d' % n)
>>> # The sequence counter starts at 0 by default
>>> UserFactory()
<User: user0>
>>> UserFactory()
<User: user1>

>>> # A value can be provided for a sequence-driven field
>>> # but this still increments the sequence counter
>>> UserFactory(username="ada.lovelace")
<User: ada.lovelace>
>>> UserFactory()
<User: user3>

Note

For more complex situations, you may also use the @sequence() decorator (note that self is not added as first parameter):

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    @factory.sequence
    def username(n):
        return 'user%d' % n

To set or reset the sequence counter see Forcing a sequence counter.

LazyFunction

In simple cases, calling a function is enough to compute the value. If that function doesn’t depend on the object being built, use LazyFunction to call that function; it should receive a function taking no argument and returning the value for the field:

class LogFactory(factory.Factory):
    class Meta:
        model = models.Log

    timestamp = factory.LazyFunction(datetime.now)
>>> LogFactory()
<Log: log at 2016-02-12 17:02:34>

>>> # The LazyFunction can be overridden
>>> LogFactory(timestamp=now - timedelta(days=1))
<Log: log at 2016-02-11 17:02:34>

Note

For complex cases when you happen to write a specific function, the @lazy_attribute() decorator should be more appropriate.

LazyAttribute

Some fields may be deduced from others, for instance the email based on the username. The LazyAttribute handles such cases: it should receive a function taking the object being built and returning the value for the field:

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    username = factory.Sequence(lambda n: 'user%d' % n)
    email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.username)
>>> UserFactory()
<User: user0 (user0@example.com)>

>>> # The LazyAttribute handles overridden fields
>>> UserFactory(username='john')
<User: john (john@example.com)>

>>> # They can be directly overridden as well
>>> UserFactory(email='doe@example.com')
<User: user2 (doe@example.com)>

Note

As for Sequence, a @lazy_attribute() decorator is available:

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    username = factory.Sequence(lambda n: 'user%d' % n)

    @factory.lazy_attribute
    def email(self):
        return '%s@example.com' % self.username

Inheritance

Once a “base” factory has been defined for a given class, alternate versions can be easily defined through subclassing.

The subclassed Factory will inherit all declarations from its parent, and update them with its own declarations:

class UserFactory(factory.Factory):
    class Meta:
        model = base.User

    firstname = "John"
    lastname = "Doe"
    group = 'users'

class AdminFactory(UserFactory):
    admin = True
    group = 'admins'
>>> user = UserFactory()
>>> user
<User: John Doe>
>>> user.group
'users'

>>> admin = AdminFactory()
>>> admin
<User: John Doe (admin)>
>>> admin.group  # The AdminFactory field has overridden the base field
'admins'

Any argument of all factories in the chain can easily be overridden:

>>> super_admin = AdminFactory(group='superadmins', lastname="Lennon")
>>> super_admin
<User: John Lennon (admin)>
>>> super_admin.group  # Overridden at call time
'superadmins'

Non-kwarg arguments

Some classes take a few, non-kwarg arguments first.

This is handled by the inline_args attribute:

class MyFactory(factory.Factory):
    class Meta:
        model = MyClass
        inline_args = ('x', 'y')

    x = 1
    y = 2
    z = 3
>>> MyFactory(y=4)
<MyClass(1, 4, z=3)>

Altering a factory’s behavior: parameters and traits

Some classes are better described with a few, simple parameters, that aren’t fields on the actual model. In that case, use a Params declaration:

class RentalFactory(factory.Factory):
    class Meta:
        model = Rental

    begin = factory.fuzzy.FuzzyDate(start_date=datetime.date(2000, 1, 1))
    end = factory.LazyAttribute(lambda o: o.begin + o.duration)

    class Params:
        duration = 12
>>> RentalFactory(duration=0)
<Rental: 2012-03-03 -> 2012-03-03>
>>> RentalFactory(duration=10)
<Rental: 2008-12-16 -> 2012-12-26>

When many fields should be updated based on a flag, use Traits instead:

class OrderFactory(factory.Factory):
    status = 'pending'
    shipped_by = None
    shipped_on = None

    class Meta:
        model = Order

    class Params:
        shipped = factory.Trait(
            status='shipped',
            shipped_by=factory.SubFactory(EmployeeFactory),
            shipped_on=factory.LazyFunction(datetime.date.today),
        )

A trait is toggled by a single boolean value:

>>> OrderFactory()
<Order: pending>
>>> OrderFactory(shipped=True)
<Order: shipped by John Doe on 2016-04-02>

Strategies

All factories support two built-in strategies:

  • build provides a local object

  • create instantiates a local object, and saves it to the database.

Note

For 1.X versions, the create will actually call AssociatedClass.objects.create, as for a Django model.

Starting from 2.0, factory.Factory.create() simply calls AssociatedClass(**kwargs). You should use DjangoModelFactory for Django models.

When a Factory includes related fields (SubFactory, RelatedFactory), the parent’s strategy will be pushed onto related factories.

Calling a Factory subclass will provide an object through the default strategy:

class MyFactory(factory.Factory):
    class Meta:
        model = MyClass
>>> MyFactory.create()
<MyFactory: X (saved)>

>>> MyFactory.build()
<MyFactory: X (unsaved)>

>>> MyFactory()  # equivalent to MyFactory.create()
<MyClass: X (saved)>

The default strategy can be changed by setting the class Meta strategy attribute.