haki
haki

Reputation: 9759

How to prevent FactoryBoy from reusing object of a SubFactory?

I have the following factories:

class UserFactory(factory.DjangoModelFactory):
    class Meta:
        model = get_user_model()


class ProProfileFactory(factory.DjangoModelFactory):
    user = factory.SubFactory(UserFactory)
    class Meta:
        model = ProfessionalProfile


class UserProfileFactory(factory.DjangoModelFactory):
    user = factory.SubFactory(UserFactory)
    class Meta:
        model = UserProfile

When I inject both pro and user profiles they are associated with the same user:

def test_should_create_project(pro_profile, user_profile):
    assert user_profile.user != pro_profile.user

This test fail.

How can I make factory boy create a new user for each profile?

I'm using Django 1.11, pytest 3.2.2, pytest-django 3.1.2, pytest-factoryboy 1.3.1

Upvotes: 2

Views: 954

Answers (1)

dinosaurwaltz
dinosaurwaltz

Reputation: 1771

You're using the auto-generated model fixtures. From the docs

Sub-factory attribute points to the model fixture of the sub-factory. Attributes of sub-factories are injected as dependencies to the model fixture and can be overridden via the parametrization.

So the model fixtures pro_profile and user_profile both use the model fixture user. Hence they are the same. I wasn't expecting this behaviour either, so I've tested a few options

Override the factory (as in docs)

@pytest.mark.parametrize('user_profile__user',
                         [LazyFixture(lambda user_factory: user_factory())])
def test_should_create_project(professional_profile, user_profile):
    assert user_profile.user != professional_profile.user

Just use the factory fixtures

def test_should_create_project_1(professional_profile_factory, user_profile_factory):
        user_profile = user_profile_factory()
        professional_profile = professional_profile_factory()
        assert user_profile.user != professional_profile.user

Change subfactory during registration

register(ProProfileFactory, 'pro_profile_2',
         user=LazyFixture(lambda user_factory: user_factory()))

def test_should_create_project_2(pro_profile_2, user_profile):
    assert user_profile.user != pro_profile_2.user

Using Partial specialization (doesn't work for me)

# oddly, this fails for me, partial specialization
register(ProProfileFactory, 'pro_profile_3')
register(UserFactory, 'another_user')

@pytest.fixture
def pro_profile_3__user(another_user):
    return another_user

# This fails
def test_should_create_project_3(pro_profile_3, user_profile):
    assert user_profile.user != pro_profile_3.user

I think the easiest way is just to use the factory fixtures user_profile_factory and pro_profile_factory as they are easiest to reason about.

Upvotes: 1

Related Questions