pytest-dev / pytest-dev/pytest-factoryboy

Generated model fixtures do not respect which SubFactory was used

Open
#257 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
400
Forks
44
Avg merge
6h 34m
Merged PRs (30d)
1

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the provided test_wrong_fixture_name reproducer and the register calls for BModelFactory, BobModelFactory, and AModelFactory. Trace how SubFactory fixture names are resolved when factory classes inherit, then verify that the fixture uses BobModelFactory and produces a b_model with name "Bob".

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.