Factory Boy can help you during testing Django Apps

During my work with the team, i learned a lot from them. Especially with CTO and my friends there. They taught me by giving a test code that is so beautiful. With Django Factory Boy I can create a shadow object during the testing phase without needing to create objects from the queryset that make it so simple.


This note gives me feedback in the future. I keep using this note for my reference in the code testing phase in Django Framework.

For installation, it’s pretty easy. I only need a package named factory_boy which includes the Faker package.

(myenv) $ pip install factory_boy

If you want to see full reference from factory_boy, you can visit this link.

How to use ?

How to use it is quite easy. In this case I have a simple model class, called Product model.

class Product(models.Model):
sku = models.CharField(max_length=30, unique=True,
primary_key=True)
name = models.CharField(max_length=30)
base_price = models.PositiveIntegerField()
price = models.PositiveIntegerField()
stock = models.PositiveIntegerField()
stock_min = models.PositiveIntegerField()
    def __str__(self):
return self.sku
    class Meta:
db_table = 'product'

Then, iwill create a tests directory. However, I need to delete the tests.py file inside my app before making it.

Then I will create a structure like this inside my app:

myapp/
tests/
factories.py
test_products_v1.py

The factories.py file contains the factory product that will create the product object as long as I call it in the testing phase. It will create as many objects as I want in testing. While the test_products_v1.py file contains the test code for the product.

The contents of the factories.py file are as follows:

import factory
import random
from factory.django import DjangoModelFactory
class ProductFactory(DjangoModelFactory):
    @factory.sequence
def sku(n):
return 'SKU-%d' % n
    @factory.sequence
def name(n):
return 'PRODUCT-%d' % n
    base_price = factory.lazy_attribute(
lambda o: random.randint(100, 2000))
price = factory.lazy_attribute(
lambda o: random.randint(1000, 20000))
stock = factory.lazy_attribute(lambda o: random.randint(1, 100))
stock_min = factory.lazy_attribute(
lambda o: random.randint(1, 5))
    class Meta:
model = myapp.Product'

Look at the fields. It’s like a field on a model that’s in the Product model. In the Meta class, there is one attribute named model. This attribute contains a value referencing my Product model that has the format <appname>. <ModelName>.

Ok, if we make the test in the file test_products_v1.py, more or less we will use the Factory class we have created earlier:

import json
from django.test import TestCase
from rest_framework.test import APITestCase
from rest_framework import status
from salesapi.tests.factories import ProductFactory
from sales.models import Product
class TestProductsV1(APITestCase):
    def test_product_list(self):
        for _ in range(3):
ProductFactory()
        response = self.client.get(
'/api-sales/products/'
)
        expected = 3
        self.assertEqual(
response.status_code, status.HTTP_200_OK)
self.assertEqual(
len(json.loads(response.content.decode('utf-8'))),
expected)

Simple and so elegant. I love it. Django & Python is fucking awesome.