1

I have a factoryboy factory for sqlalchemy model which uses faker

from faker import Faker
from db_init import session

fake = Faker()

class ClientAppFactory(factory.alchemy.SQLAlchemyModelFactory):
    class Meta:
        model = ClientApp
        sqlalchemy_session = session
        sqlalchemy_session_persistence = 'commit'

    name = fake.word()
    display_name = fake.word()

This factory creates rows in database. Field name of my model must be unique. When I call my factory several times in a row, I get several instances with the same name. How can I get different names in my instances?

import pytest
from pytest_factoryboy import register

register(ClientAppFactory)

@pytest.fixture
def several_client_apps():
    ca1 = client_app_factory()
    ca2 = client_app_factory()

In this case I get error about name field unique constraint.

  • Does this answer your question? [How to use Faker from Factory\_boy](https://stackoverflow.com/questions/38687492/how-to-use-faker-from-factory-boy) – Mark Aug 15 '21 at 18:20

2 Answers2

0

I found an answer. Factory has method build which redefine factory attributes every time when you call it.

@pytest.fixture
def several_client_apps():
    ca1 = client_app_factory.build()
    ca2 = client_app_factory.build()
  • Read here about using build https://factoryboy.readthedocs.io/en/stable/reference.html?highlight=Build#factory.BUILD_STRATEGY . Also consider using `factory.Faker('name')` as per the other question I linked. – Mark Aug 15 '21 at 18:55
  • `build` won't create the row in database though – hectorcanto Oct 08 '21 at 10:22
0

This is a common mistake with factoryboy and `faker.

Using faker.Faker in a Factory will establish a fixed value on the definition of the class. What you want instead is to use factory.Faker or delay any faker.Faker execution with a lazy function.

An example with both strategies:

from faker import Faker
import factory

fake = Faker()
word_list = ["one", "two", "three"]

class ExampleFactory(factory.DictFactory):

    name = factory.Faker("word")
    display_name = factory.LazyFunction(fake.word)
    another_name = factory.LazyFunction(lambda: fake.word(word_list))

ExampleFactory.bu()
ExampleFactory.create_batch(5)

I used a DictFactory to make it simpler to test, but it should work with model-based factories too.

The another_name field uses a lambda to be able to add parameters to the fake method.

hectorcanto
  • 1,987
  • 15
  • 18