Python tutorial on the FactoryBoy library, covering basic and advanced usage for generating test data with practical examples.
last modified March 11, 2025
The FactoryBoy library in Python is a powerful tool for generating test data. It allows you to create model instances with realistic, randomized, or predefined data, making it ideal for testing and development. This tutorial covers basic and advanced usage of FactoryBoy with practical examples.
FactoryBoy is particularly useful for creating fixtures, populating databases, and generating test cases for unit and integration tests.
To use FactoryBoy, you need to install it first. You can install it using pip:
pip install factory_boy
This example generates test data for a customer in an e-commerce system.
basic_factory.py
import factory
class Customer: def init(self, full_name, email, phone): self.full_name = full_name self.email = email self.phone = phone
class CustomerFactory(factory.Factory): class Meta: model = Customer
full_name = factory.Faker("name")
email = factory.Faker("email")
phone = factory.Faker("phone_number")
customer = CustomerFactory() print(f"Customer: {customer.full_name}, Email: {customer.email}, Phone: {customer.phone}")
In this practical example, the CustomerFactory creates Customer instances with realistic data for an e-commerce platform. The Faker provider generates random full names, emails, and phone numbers, mimicking real customer profiles.
This is useful for testing features like user registration or order processing without manually crafting test data. The factory simplifies setup for unit tests by providing consistent, varied inputs, saving time and reducing errors in test preparation.
This example creates test users for a Django-based blog application.
django_factory.py
import factory from django.contrib.auth.models import User
class BlogUserFactory(factory.django.DjangoModelFactory): class Meta: model = User
username = factory.Faker("user_name")
email = factory.Faker("email")
first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
is_active = True
user = BlogUserFactory() print(f"Blog User: {user.username}, Email: {user.email}, Active: {user.is_active}")
Here, the BlogUserFactory generates User instances for a Django blog app. It uses DjangoModelFactory to integrate with Django’s ORM, creating users with random usernames, emails, and names, plus a fixed is_active status.
This is practical for testing authentication, permissions, or post creation in a blog system. By setting is_active=True, the factory ensures users are ready for login tests, while Faker provides diverse data to simulate real user scenarios.
This example generates discounted products for an online store’s test suite.
custom_factory.py
import factory
class Product: def init(self, name, original_price): self.name = name self.original_price = original_price
class ProductFactory(factory.Factory): class Meta: model = Product
name = factory.Faker("catch_phrase")
original_price = factory.Faker("pydecimal", left_digits=3, right_digits=2, positive=True)
@factory.post_generation
def apply_sale(self, create, extracted, **kwargs):
if extracted:
self.original_price *= 0.85 # Apply 15% discount
sale_product = ProductFactory(apply_sale=True) print(f"Product on Sale: {sale_product.name}, Price: ${sale_product.original_price}")
In this scenario, the ProductFactory creates Product instances with catchy names and prices. The post_generation hook apply_sale optionally applies a 15% discount, simulating a sale event in an online store.
This customization is valuable for testing pricing logic or promotional features. By using apply_sale=True, developers can generate discounted products on demand, ensuring test coverage for both regular and sale prices without duplicating factory definitions.
This example generates unique invoice numbers for an accounting system.
sequence_factory.py
import factory
class Invoice: def init(self, invoice_number, client_name): self.invoice_number = invoice_number self.client_name = client_name
class InvoiceFactory(factory.Factory): class Meta: model = Invoice
invoice_number = factory.Sequence(lambda n: f"INV-{n:04d}")
client_name = factory.Faker("company")
invoice1 = InvoiceFactory() invoice2 = InvoiceFactory() print(f"Invoice 1: {invoice1.invoice_number}, Client: {invoice1.client_name}") print(f"Invoice 2: {invoice2.invoice_number}, Client: {invoice2.client_name}")
The InvoiceFactory generates Invoice objects with unique invoice numbers (e.g., INV-0001, INV-0002) using factory.Sequence. The client names are random company names from Faker, simulating real billing data.
This is ideal for testing financial systems where invoices must have distinct identifiers. The sequence ensures no duplicates, mimicking a production environment, while Faker adds variety to client names for comprehensive test scenarios.
This example creates test data for a student and their enrolled course.
subfactory_example.py
import factory
class Course: def init(self, title, code): self.title = title self.code = code
class Student: def init(self, name, course): self.name = name self.course = course
class CourseFactory(factory.Factory): class Meta: model = Course
title = factory.Faker("job") # Using job titles as course names
code = factory.Sequence(lambda n: f"CS{n:03}")
class StudentFactory(factory.Factory): class Meta: model = Student
name = factory.Faker("name")
course = factory.SubFactory(CourseFactory)
student = StudentFactory() print(f"Student: {student.name}, Course: {student.course.title} ({student.course.code})")
In this example, the CourseFactory generates Course objects with job-like titles and unique codes (e.g., CS001). The StudentFactory uses a SubFactory to link each Student to a Course, simulating enrollment in an educational system.
This is practical for testing student management systems or course registration features. The subfactory approach ensures relational data consistency, allowing developers to test interactions between students and courses without manually creating related objects.
This example creates test orders with associated items for an e-commerce test suite.
order_items_factory.py
import factory
class Item: def init(self, name, quantity): self.name = name self.quantity = quantity
class Order: def init(self, order_id, items): self.order_id = order_id self.items = items
class ItemFactory(factory.Factory): class Meta: model = Item
name = factory.Faker("word")
quantity = factory.Faker("pyint", min_value=1, max_value=10)
class OrderFactory(factory.Factory): class Meta: model = Order
order_id = factory.Sequence(lambda n: f"ORD-{n:05}")
items = factory.List([factory.SubFactory(ItemFactory) for _ in range(2)])
order = OrderFactory() print(f"Order ID: {order.order_id}") for item in order.items: print(f"Item: {item.name}, Quantity: {item.quantity}")
The ItemFactory generates Item objects with random names and quantities (1-10). The OrderFactory creates Order instances with unique order IDs and a fixed list of two items using factory.List and SubFactory.
This is highly practical for testing order processing or inventory management in e-commerce applications. The factory simulates a realistic order with multiple items, allowing developers to test order totals, stock updates, or checkout flows efficiently.
By fixing the item count at two, the example keeps output manageable, but the approach can be extended to variable lengths for more complex test cases, enhancing flexibility in test design.
This example generates test tickets with dynamic resolution times for a support system.
lazy_attribute_factory.py
import factory from datetime import datetime, timedelta
class SupportTicket: def init(self, ticket_id, issue, created_at, resolved_at): self.ticket_id = ticket_id self.issue = issue self.created_at = created_at self.resolved_at = resolved_at
class SupportTicketFactory(factory.Factory): class Meta: model = SupportTicket
ticket_id = factory.Sequence(lambda n: f"TICKET-{n:03}")
issue = factory.Faker("sentence")
created_at = factory.Faker("date_time_this_year")
resolved_at = factory.LazyAttribute(lambda obj: obj.created_at + timedelta(days=factory.Faker("pyint", min_value=1, max_value=7).generate()))
ticket = SupportTicketFactory() print(f"Ticket: {ticket.ticket_id}, Issue: {ticket.issue}") print(f"Created: {ticket.created_at}, Resolved: {ticket.resolved_at}")
The SupportTicketFactory creates SupportTicket instances with unique ticket IDs, random issues, and dynamic timestamps. The created_at field uses Faker for a date this year, while resolved_at is calculated with LazyAttribute to be 1-7 days after creation.
This is useful for testing support ticket workflows, such as response times or resolution tracking. The lazy attribute ensures the resolved time is logically consistent with the creation time, simulating real ticket lifecycles without hardcoding values.
The try-catch block isn’t needed here since no exceptions are thrown, but the factory’s dynamic nature makes it adaptable for testing time-based features or reporting in a helpdesk application.
Use for Test Data: Use FactoryBoy to generate realistic test data for unit and integration tests.
Customize Factories: Customize factories to match your application’s data requirements.
Use Sequences for Uniqueness: Use sequences to ensure unique values for fields like IDs or usernames.
Leverage SubFactories: Use subfactories to create related objects and maintain data consistency.
In this article, we have explored various examples of using the Python FactoryBoy library for generating test data, including basic usage, Django integration, customization, sequences, and subfactories.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.