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 ``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


.. code-block:: python

    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:

.. code-block:: pycon

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

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

.. code-block:: pycon

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


A given class may be associated to many :class:`~factory.Factory` subclasses:

.. code-block:: python

    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'


.. code-block:: pycon

    >>> 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 :class:`~factory.Sequence` declaration:

.. code-block:: python

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

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

.. code-block:: pycon

    >>> # 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 :meth:`@factory.sequence <factory.sequence>` decorator (note that ``self`` is not added as first parameter):

          .. code-block:: python

            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 :ref:`Forcing a sequence counter <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 :class:`~factory.LazyFunction` to call that function; it should receive a function taking no
argument and returning the value for the field:

.. code-block:: python

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

        timestamp = factory.LazyFunction(datetime.now)

.. code-block:: pycon

    >>> 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 :meth:`@factory.lazy_attribute <factory.lazy_attribute>` decorator should be more appropriate.


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):
        class Meta:
            model = models.User

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

.. code-block:: pycon

    >>> 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 :class:`~factory.Sequence`, a :meth:`@factory.lazy_attribute <factory.lazy_attribute>` decorator is available:


.. code-block:: python

    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 :class:`~factory.Factory` will inherit all declarations from its parent,
and update them with its own declarations:

.. code-block:: python

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

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

    class AdminFactory(UserFactory):
        admin = True
        group = 'admins'

.. code-block:: pycon

    >>> 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:

.. code-block:: pycon

    >>> 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 :data:`~factory.FactoryOptions.inline_args` attribute:

.. code-block:: python

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

        x = 1
        y = 2
        z = 3

.. code-block:: pycon

    >>> 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 :attr:`~factory.Factory.Params` declaration:

.. code-block:: python

    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

.. code-block:: pycon

    >>> 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 :class:`Traits <factory.Trait>` instead:

.. code-block:: python

    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:

.. code-block:: pycon

    >>> 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, :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):
        class Meta:
            model = MyClass

.. code-block:: pycon

    >>> 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`` :attr:`~factory.FactoryOptions.strategy` attribute.
