42

Factory_boy uses fake-factory (Faker) to generate random values, I would like to generate some random values in my Django tests using Faker directly.

Factory_boy docs suggests using factory.Faker and its provider as :

class RandomUserFactory(factory.Factory):
    class Meta:
        model = models.User

    first_name = factory.Faker('first_name')

But this isn't generating any name:

>>> import factory
>>> factory.Faker('name')
<factory.faker.Faker object at 0x7f1807bf5278>
>>> type(factory.Faker('name'))
<class 'factory.faker.Faker'>

From factory_boy faker.py class factory.Faker('ean', length=10) calls faker.Faker.ean(length=10) but Faker docs says it should show a name:

from faker import Faker
fake = Faker()
fake.name()
# 'Lucy Cechtelar'

Is there any other way to use Faker instead of setting an instance directly from Faker?

from faker import Factory
fake = Factory.create()
fake.name()

5 Answers 5

32

I know this is an old question but for anyone who might come across this, here's another approach that you can use.

>>> from factory.faker import faker
>>> FAKE = faker.Faker()
>>> FAKE.name()
'Scott Rodriguez'
>>> FAKE.address()
'PSC 5061, Box 1673\nAPO AP 53007'
>>>
3
  • 2
    This is what I wanted to know when I asked the question.
    – marcanuy
    Commented Jan 22, 2019 at 14:05
  • 2
    I think from factory.faker import faker is no different then import faker. From the standpoint of reproducibility I suppose it's better to use the instance that the factory_boy itself creates.
    – x-yuri
    Commented Apr 6, 2019 at 12:18
  • I agree with @x-yuri - it's nother related to the factoryboy's inner Faker
    – Nam G VU
    Commented Aug 18, 2021 at 10:21
31

You can use faker with factory_boy like this:

class RandomUserFactory(factory.Factory):
    class Meta:
        model = models.User

    first_name = factory.Faker('first_name')

user = RandomUserFactory()

print user.first_name
# 'Emily'

So you need to instantiate a user with factory_boy and it will call Faker for you.

I don't know if you are trying to use this with Django or not, but if you want the factory to save the created user to the database, then you need to extend factory.django.DjangoModelFactory instead of factory.Factory.

2
  • 2
    You just repeated what the OP already know. Maybe I misunderstand things here cause you have 25 upvotes ^^
    – Nam G VU
    Commented Aug 18, 2021 at 10:24
  • @NamGVU I do repeat the class but the last 2 lines show how can you generate fake data trough the Factory instead of using the faker library directly.
    – rlaszlo
    Commented Aug 18, 2021 at 11:42
12

factory_boy doesn't provide a public/documented interface to get to the Faker instances it uses. So preferably create yourself a separate one. But in case you really need to:

import factory
print(factory.Faker._get_faker().random_int())
print(factory.Faker._get_faker('en_US').random_int())

You can also use generate()/evaluate(), but the interface changed with time:

# 3.0.1
# uses self.locale
print(factory.Faker('random_int').generate())
print(factory.Faker('random_int').evaluate(None, None, None))
print(factory.Faker('random_int', locale='en_US').generate())
print(factory.Faker('random_int', locale='en_US').evaluate(None, None, None))

# 3.1.0
# uses locale from the parameters
print(factory.Faker('random_int').generate({'locale': None}))
print(factory.Faker('random_int').evaluate(None, None, {'locale': None}))
print(factory.Faker('random_int').generate({'locale': 'en_US'}))
print(factory.Faker('random_int').evaluate(None, None, {'locale': 'en_US'}))

# 3.2.0, 3.2.1
# no generate()
print(factory.Faker('random_int').evaluate(None, None, {'locale': None}))
print(factory.Faker('random_int').evaluate(None, None, {'locale': 'en_US'}))

You may also check out the other answer for a more detailed example.

4
  • 4
    This no longer works in later Faker versions unfortunately.
    – jaywink
    Commented Jan 1, 2021 at 16:50
  • This should be the accepted answer in my view.
    – Nam G VU
    Commented Aug 19, 2021 at 6:27
  • Is there anyway to avoid using private method _get_faker()? :)
    – hungneox
    Commented Feb 27, 2023 at 6:48
  • 1
    @hungneox Updated the answer. That's all the options I can see. There's also this answer, but I guess that's not what you want.
    – x-yuri
    Commented Mar 3, 2023 at 17:57
4

First, if you want to use factory_boy with a Django model, you should use DjangoModelFactory as it is recommended.

Second, factory_boy also suggests to use Faker attribute declaration in order to easily define realistic-looking factories. (see providers)

class RandomUserFactory(factory.DjangoModelFactory):
    class Meta:
        model = 'myapp.User'  # Equivalent to model = myapp.models.User

    first_name = factory.Faker('first_name')

Once you have defined your factory, you can simply use it as follows:

>>> o = RandomUserFactory()
>>> o.first_name
Tim
1
  • 3
    How would you do this if you are using a LazyAttribute? E.g. factory.LazyAttribute(lambda a: factory.Faker('sentence')...
    – alias51
    Commented Oct 15, 2021 at 20:13
3

As the other answers have already clarified, the proper/usual way to use Faker is with factories. However, it is occasionally useful to be able to use Faker inline, and that seems to be the underlying question here.

Here is an updated answer for 2022 and latest factoryboy versions:

from typing import Any

from factory import Faker


def get_fake(provider: str, locale: str | None = None) -> Any:
     """ e.g. `get_fake('name')` ==> 'Buzz Aldrin' """
    if not locale:
        locale = Faker._DEFAULT_LOCALE  # pylint: disable=protected-access
    return Faker(provider).evaluate({}, None, {'locale': locale})
1
  • It defaults to Faker._DEFAULT_LOCALE anyway. The first argument to evaluate() can be None. More info in my answer.
    – x-yuri
    Commented Mar 3, 2023 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.