30
loading...
This website collects cookies to deliver better user experience
pip install factory-boy
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.
dataclass
in python. Create an empty directory named data
and also add __init__.py
file inside to mark it as a python package. We'll follow the example above which Post
instances.from dataclasses import dataclass
@dataclass
class Post:
title: str
description: str
published: bool
image: str
dataclass
:dataclass
module is introduced in Python 3.7 as a utility tool to make structured classes specially for storing data - geeksforgeeks.org
dataclass
which holds four attributes. Now, this class needs a factory where we can create mocked instances.import factory
import factory.fuzzy
from data.models import Post
class PostFactory(factory.Factory):
class Meta:
model = Post
title = factory.Faker("name")
description = factory.Faker("sentence")
published = factory.fuzzy.FuzzyChoice(choices=[True, True, True, False])
image = factory.Faker("image_url")
factory.django.DjangoModelFactory
class instead of just factory.Factory
.model = Post
that defines the particular class we are going to mock.FuzzyAttributes
. However, in newer versions of factory_boy
, they also included Faker
class where you can use it to generate fake data. So, we used a few of them to mock our fields with fake data.from data.factories import PostFactory
posts = PostFactory.create_batch(10)
for post in posts:
print(post)
create_batch
function takes a number (size) of generated items and allows override the factory class attributes.python main.py
Post(title='Tracy Hernandez', description='Similar house wind bit win anything process even.', published=True, image='https://placekitten.com/209/389')
Post(title='Kimberly Henderson', description='Behavior wife phone agency door.', published=True, image='https://www.lorempixel.com/657/674')
Post(title='Jasmine Williams', description='Action experience cut loss challenge.', published=True, image='https://placekitten.com/365/489')
Post(title='Nicholas Moody', description='Consumer language approach risk event lose.', published=True, image='https://placekitten.com/756/397')
Post(title='Dr. Curtis Monroe', description='Firm member full.', published=True, image='https://dummyimage.com/238x706')
Post(title='David Martin', description='Join fall than.', published=False, image='https://dummyimage.com/482x305')
Post(title='Seth Oliver', description='Including most join resource heavy.', published=True, image='https://www.lorempixel.com/497/620')
Post(title='Daniel Berger', description='Summer mean figure husband read.', published=True, image='https://dummyimage.com/959x180')
Post(title='Samantha Romero', description='Window leader subject defense lawyer.', published=False, image='https://placeimg.com/965/518/any')
Post(title='Jessica Carroll', description='Would try religious opportunity future blood our.', published=True, image='https://placekitten.com/911/434')
factory_boy
that you're going to test rather than create thousands of fixtures ( JSON files that hold dummy data ). Assuming that, in future, you'll have critical changes in your models where all these JSON objects must be refactored to fit the current state.factories.py
inside the tests
directory for each app.None
if they don't require initial values:import factory
import factory.django
from blog.models import Post
class PostFactory(factory.django.DjangoModelFactory):
title = factory.Faker('name')
image_url = factory.Faker('image_url')
tags = None
class Meta:
model = Post
PostFactory(
tags=['spacex', 'tesla']
)
create_batch
also receives kwargs
where it allows overriding attributes:PostFactory.create_batch(
5, #number of instances
tags=['spacex', 'tesla'] #override attr
)
Comment
model has a field post
as a foreign key where it built from Post
object. At this point, we can use post_generation
hook to assign created post
instance to CommentFactory
. Don't confuse the name conventions here:post_generation
is a built-in decorator that allows doing stuff with generated factory instance.post
object is an instance of PostFactory
that we are using as an example.import factory
import factory.fuzzy
from blog.models import Post, Comment
class CommentFactory(factory.django.DjangoModelFactory):
class Meta:
model = Comment
post = None
message = factory.Faker("sentence")
class PostFactory(factory.Factory):
class Meta:
model = Post
title = factory.Faker("name")
description = factory.Faker("sentence")
published = factory.fuzzy.FuzzyChoice(choices=[True, True, True, False])
image = factory.Faker("image_url")
@factory.post_generation
def post_related_models(obj, create, extracted, **kwargs):
if not create:
return
CommentFactory.create(
post=obj
)
obj
is the Post
object previously generatedcreate
is a boolean indicating which strategy was usedextracted
is None
unless a value was passed in for the PostGeneration
declaration at Factory
declaration timekwargs
are any extra parameters passed as attr__key=value
when calling the Factory
slug
where you can't use upper case or any hyphens. There is a decorator named @factory.lazy_attribute
which kind of behaves like lambda
:from django.utils.text import slugify
class PostFactory(factory.django.DjangoModelFactory):
class Meta:
model = Post
title = factory.Faker("name")
description = factory.Faker("sentence")
published = factory.fuzzy.FuzzyChoice(choices=[True, True, True, False])
image = factory.Faker("image_url")
@factory.lazy_attribute
def slug(self):
return slugify(self.title)
instance.slug
kwargs
of instance. Assume that you need to concatenate post title with _example
string:class PostFactory(factory.Factory):
class Meta:
model = Post
title = factory.Faker("name")
description = factory.Faker("sentence")
published = factory.fuzzy.FuzzyChoice(choices=[True, True, True, False])
image = factory.Faker("image_url")
@classmethod
def _adjust_kwargs(cls, **kwargs):
kwargs['title'] = f"{kwargs['title']}_example"
return kwargs
factory.lazy_attribute
but in some cases, you'll need access to the instance attributes after its generated but not while generation.