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 recipes
, while those needing detailed documentation will be interested in the reference
section.
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.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)>
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 ~factory.Sequence
declaration:
class UserFactory(factory.Factory):
class Meta:
model = models.User
username = factory.Sequence(lambda n: 'user%d' % n)
>>> UserFactory()
<User: user0>
>>> UserFactory()
<User: user1>
Note
For more complex situations, you may also use the ~factory.@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
In simple cases, calling a function is enough to compute the value. If that function doesn't depend on the object being built, use ~factory.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 overriden
>>> 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 ~factory.@lazy_attribute
decorator should be more appropriate.
Some fields may be deduced from others, for instance the email based on the username. The ~factory.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: user1 (user1@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: user3 (doe@example.com)>
Note
As for ~factory.Sequence
, a ~factory.@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
Once a "base" factory has been defined for a given class, alternate versions can be easily defined through subclassing.
The subclassed ~factory.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'
Some classes take a few, non-kwarg arguments first.
This is handled by the ~factory.FactoryOptions.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)>
Some classes are better described with a few, simple parameters, that aren't fields on the actual model. In that case, use a ~factory.Factory.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 <factory.Trait>
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>
All factories support two built-in strategies:
build
provides a local objectcreate
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 ~factory.django.DjangoModelFactory
for Django models.
When a ~factory.Factory
includes related fields (~factory.SubFactory
, ~factory.RelatedFactory
), the parent's strategy will be pushed onto related factories.
Calling a ~factory.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
~factory.FactoryOptions.strategy
attribute.