Sunday 23 February 2014

Factory Boy !

This Post we are gonna talk about FactoryBoy, Although the original documentation on FactoryBoy website is very good, short and precise , but still here are some quick notes which would get you started and for any Reference would be much useful.

So What is FactoryBoy ?

FactoryBoy provides a default way of getting new Instances,while still being able to override some fields on per-call basis.

Advantages ?

  1. Particularly useful in handling situations which require creation of object, interacting with database, it provides safe/better way for data population and instance creation.
  2. Provides support for multiple build strategies (saved/unsaved, attribute dicts, stubbed objects)
  3. Powerful helpers (sequence, sub-factories, reverse dependencies), which we are going to talk about later in this post.

Let's start with an example:

We have a model object Poll which has
  • A polling question
  • Date on which Poll is published
  • A function to check if the poll was published recently

To tests such kind of an object we can create tests like
  • Create a poll with future publishing date and check if it was published recently
  • Create a poll with past publishing date and check if it was published recently
  • Create a poll with recent publishing date and check if it was published recently

This test could be easily modified to use factories like:
Define factory classes to make instances in factories.py like:

As in above example factories declare a set of attributes used to instantiate an object, whose class is defined
in FACTORY_FOR attribute.
A given class might be associated to many factory subclasses by having different default values for attributes in Factory class example
A User class might be related to Userfactory(), FemaleUserFactory(), MaleUserFactory()
each having different value for the gender attribute.

Now after creating a factory we can modify our tests to use the factory class to instantiate a new object like

As is visible it is possible to override the default values for attributes in factory class by passing new values for these attributes example
Value for pub_date is passed in this case to create a post with past date.

Some of the helper functions come handy with factory class are:

Sequence declaration:

When a field has a unique key its value must be different, thus these unique values can generated like
username = factory.Sequence(lambda n: 'user%d' % n)

Lazy Attribute:

For fields deduced from other fields like
username = factory.Sequence(lambda n: 'user%d' % n)
email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.username)
Here email is deduced from username

Inheritance:

Same as normal inheritance, we can override attributes for parent class

Non-kwarg arguments:

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

Strategies:

Factories support two built-in strategies
MyFactory.create() provide a local object and saves it to database
MyFactory.build() provide a local object


Database dependency issues:

Dependent objects(Foreign keys):

first_name = factory.Sequence(lambda n: "Agent %03d" % n)
group = factory.SubFactory(GroupFactory)
Here the group attribute is a foreign key for user table and thus it becomes a SubFactory in factory class.

Other such issues like

Reverse Dependencies(Reverse Foreign Keys)

When a related object should be created upon object creation

Simple ManytoMany

Building the adequate link between two models depends heavily on the use case

ManytoMany with a 'through'

do exists. Examples for which can be found here

Fuzzy Attributes:

These are used to create random data for various datatypes and also while creating this data we can specify some limits so that we can generate it according to our needs. example
fi = FuzzyInteger(0, 42)
fdt = FuzzyDateTime(datetime.datetime(2008, 1, 1, tzinfo=UTC))

Thus this is a very quick introduction to FactoryBoy, which makes it clear what is it used for and how to use it.

There are many other attributes, functions, and strategies which are discussed in detailed documentation with some very good examples to get a deep insight.