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 :doc:`recipes`, while those needing detailed documentation will be interested in the :doc:`reference` section. Basic usage ----------- Factories declare a set of attributes used to instantiate an object, whose class is defined in the FACTORY_FOR attribute: - Subclass ``factory.Factory`` (or a more suitable subclass) - Set its ``FACTORY_FOR`` attribute to the target class - Add defaults for keyword args to pass to the associated class' ``__init__`` method .. code-block:: python import factory from . import base class UserFactory(factory.Factory): FACTORY_FOR = base.User firstname = "John" lastname = "Doe" You may now get ``base.User`` instances trivially: .. code-block:: pycon >>> john = UserFactory() It is also possible to override the defined attributes by passing keyword arguments to the factory: .. code-block:: pycon >>> jack = UserFactory(firstname="Jack") A given class may be associated to many :class:`~factory.Factory` subclasses: .. code-block:: python class EnglishUserFactory(factory.Factory): FACTORY_FOR = base.User firstname = "John" lastname = "Doe" lang = 'en' class FrenchUserFactory(factory.Factory): FACTORY_FOR = base.User firstname = "Jean" lastname = "Dupont" lang = 'fr' .. code-block:: pycon >>> EnglishUserFactory() >>> FrenchUserFactory() 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 :class:`~factory.Sequence` declaration: .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = models.User username = factory.Sequence(lambda n: 'user%d' % n) .. code-block:: pycon >>> UserFactory() >>> UserFactory() .. note:: For more complex situations, you may also use the :meth:`~factory.@sequence` decorator (note that ``self`` is not added as first parameter): .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = models.User @factory.sequence def username(n): return 'user%d' % n LazyAttribute ------------- Some fields may be deduced from others, for instance the email based on the username. The :class:`~factory.LazyAttribute` handles such cases: it should receive a function taking the object being built and returning the value for the field: .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = models.User username = factory.Sequence(lambda n: 'user%d' % n) email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.username) .. code-block:: pycon >>> UserFactory() >>> # The LazyAttribute handles overridden fields >>> UserFactory(username='john') >>> # They can be directly overridden as well >>> UserFactory(email='doe@example.com') .. note:: As for :class:`~factory.Sequence`, a :meth:`~factory.@lazy_attribute` decorator is available: .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = 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 :class:`~factory.Factory` will inherit all declarations from its parent, and update them with its own declarations: .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = base.User firstname = "John" lastname = "Doe" group = 'users' class AdminFactory(UserFactory): admin = True group = 'admins' .. code-block:: pycon >>> user = UserFactory() >>> user >>> user.group 'users' >>> admin = AdminFactory() >>> admin >>> admin.group # The AdminFactory field has overridden the base field 'admins' Any argument of all factories in the chain can easily be overridden: .. code-block:: pycon >>> super_admin = AdminFactory(group='superadmins', lastname="Lennon") >>> super_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 :data:`~factory.Factory.FACTORY_ARG_PARAMETERS` attribute: .. code-block:: python class MyFactory(factory.Factory): FACTORY_FOR = MyClass FACTORY_ARG_PARAMETERS = ('x', 'y') x = 1 y = 2 z = 3 .. code-block:: pycon >>> MyFactory(y=4) 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, :meth:`factory.Factory.create` simply calls ``AssociatedClass(**kwargs)``. You should use :class:`~factory.django.DjangoModelFactory` for Django models. When a :class:`~factory.Factory` includes related fields (:class:`~factory.SubFactory`, :class:`~factory.RelatedFactory`), the parent's strategy will be pushed onto related factories. Calling a :class:`~factory.Factory` subclass will provide an object through the default strategy: .. code-block:: python class MyFactory(factory.Factory): FACTORY_FOR = MyClass .. code-block:: pycon >>> MyFactory.create() >>> MyFactory.build() >>> MyFactory() # equivalent to MyFactory.create() The default strategy can ba changed by setting the class-level :attr:`~factory.Factory.FACTROY_STRATEGY` attribute.