Skip to content

Generated model fixtures do not respect which SubFactory was used #257

@ryancausey

Description

@ryancausey

Continuation of #91 as I believe it was closed in error and I cannot reopen it.

The issue still remains that if a Factory class has a SubFactory defined that is a subclass of a different factory, the generated fixture does not correctly insert the right sub factory. Here is an example:

Code sample with failing test
import factory
from pytest_factoryboy import register


class AModel:
    """Simple model that refers to another model"""

    def __init__(self, b_model):
        self.b_model = b_model


class BModel:
    """The referred to model by A that has a name."""

    def __init__(self, name):
        self.name = name


class BModelFactory(factory.Factory):
    """Factory that creates B models."""

    class Meta:
        model = BModel

    name = "John"

class BobModelFactory(BModelFactory):
    """Factory class inheritance to create a specialized model factory as recommended by
    the FactoryBoy docs.
    https://factoryboy.readthedocs.io/en/stable/introduction.html#inheritance
    """
    name = "Bob"

class AModelFactory(factory.Factory):
    """Factory that creates A models using a SubFactory to set the b_model attribute."""

    class Meta:
        model = AModel

    b_model = factory.SubFactory(BobModelFactory)


register(BModelFactory)
register(BobModelFactory, "b_model_bob")
register(AModelFactory)


def test_wrong_fixture_name(a_model):
    """This test fails because the a_model.b_model fixture ends up being BModelFactory
    instead of the BobModelFactory that is defined as the SubFactory in AModelFactory.
    """
    assert a_model.b_model.name == "Bob"

I believe the issue follows from:

  1. pytest-factoryboy uses the model class's name, not the factory class's name, to define the model fixture name. This means that any factory classes that inherit from a common factory class will overwrite any previously registered model factory fixtures with the most recently registered factory.
  2. To avoid the naming issue, factory subclasses of the common parent must be registered with a different model fixture name.
  3. Since the subfactory fixture name lookup seems to be based on the model class's name and not the factory class's name, the resolved subfactory fixture name ends up using the wrong model fixture.

The lazy fixture suggestion using partial fixture specialization during register seems like a valid workaround, but is not what I would consider the fix. It is surprising behavior that I can define AModelFactory to use BobModelFactory as the sub factory, but instead get BModelFactory used as the subfactory because of how pytest-factoryboy generates and resolves fixtures. This kind of factory inheritance and sub factory usage works as expected when using factoryboy directly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions