Factory boy makes it easy to create objects when you need them for tests.For example..
lets say you have this set of models,
from django.db import models
class Owner(models.Model):
    name = models.CharField(max_length=200)
    phone = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name
class Car(models.Model):
    name = models.CharField(max_length=200)
    owner = models.ForeignKey(Owner)
    def __unicode__(self):
        return self.name
Then your factories.py for these two will correspond to something like this
import factory
from models import Owner, Car
class OwnerFactory(factory.Factory):
    FACTORY_FOR = Owner
    name = 'bruce'
    phone = '+254728037573'
class CarFactory(factory.Factory):
    FACTORY_FOR = Car
    name = 'jeep'
    owner = factory.lazy_attribute(lambda a: OwnerFactory())
The tests for the factories themselves go something like this
from models import Car,Owner
from django.test.testcases import TestCase
class FactoryTestCase(TestCase):
    def test_car_factory(self):
        car = CarFactory()
        self.assertTrue(isinstance(car, Car))
    def test_owner_factory(self):
        owner = OwnerFactory()
        self.assertTrue(isinstance(owner, Owner))
Many to many fields are a bit tricky to emulate but this does the trick.
For instance lets say you have this set of models.
from django.db import models
class Pizza(models.Model):
    name = models.CharField(max_length=120)
    toppings = models.ManyToManyField(Topping)
    def __unicode__(self):
        return self.name
class Topping(models.Model):
    name = models.CharField(max_length=200)
    def __unicode__(self):
        return self.name
Then your factories will go something like this.
from models import Pizza, Topping
import factory
class ToppingFactory(factory.Factory):
    FACTORY_FOR = Topping
    name = 'mushrooms'
class PizzaFactory(factory.Factory):
    FACTORY_FOR = Pizza
    name = 'mushroom delight'
    @classmethod
    def _prepare(cls, create, **kwargs):
        topping = ToppingFactory()
        pizza = super(PizzaFactory, cls)._prepare(create, **kwargs)
        pizza.toppings.add(topping)
        return pizza
So the key here is to override the _prepare method and assign the manytomanyfield objects here, since you have and instance of the object.
In conclusion factories are a good alternative to fixtures when used in the right way.
Could you be so kind and share a link to other resources concerning this subject in case you happen to know any.
ReplyDelete