You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have an existing fixture that will automatically create a test database and return a client attached to that database for a test, and destroy the test database afterwards. I want to use this fixture to build a Django-like model factory, but I'm running into issues with how to inject this fixture's return value into the Factory.
Here's what I've come up with so far:
# factories.pyclassFaunaFactory(factory.Factory):
"""This class overrides the default Factory to save the object to Fauna when the strategy is `create`. This expects the `Meta.model` of the inheriting class to be set to `named_model(dict, "name here")`. """classMeta:
abstract=True# This is expected to be injected via pytest-factoryboy fixture specialization.fauna_test_client=None@classmethoddef_create(cls, model_class, *args, **kwargs):
"""This overrides the normal _create so we can instead save the data to Fauna and return the created document. """data=super()._create(model_class, *args, **kwargs)
# Remove the fauna test client from the data.fauna_test_client=data.pop("fauna_test_client")
# Use it to store the data in fauna and return the result.returnfauna_test_client.query(
fql(
""" let collection = Collection(${collection_name}) collection.create(${kwargs}) """,
collection_name=model_class.__name__,
kwargs=data,
)
).data@classmethoddef_build(cls, model_class, *args, **kwargs):
"""This overrides the normal _build so we can remove the `fauna_test_client` key/value pair from the data, as this is only used internally when actually creating the object in fauna. """data=super()._build(model_class, *args, **kwargs)
deldata["fauna_test_client"]
returndata# conftest.pyforfactory_classin (
AccountFactory,
CustomerFactory,
FalseAlarmFeeScheduleItemFactory,
FalseAlarmSchedulePeriodFactory,
LateFeeScheduleItemFactory,
PermitFeeScheduleItemFactory,
):
register(factory_class, fauna_test_client=LazyFixture("fauna_test_client_with_fsl"))
This is janky, because it only applies the lazy fixture to the model fixture, and not the factory fixture. I attempted to rectify this by overriding the factory fixture like so:
# conftest.py@pytest.fixturedeffixup_factory_fixture(fauna_test_client_with_fsl):
"""Fixup the provided factory such that it replaces the pytest-factoryboy provided factory fixture. Since we haven't found a good way to inject the `fauna_test_client` arg without having it be an actual argument to the factory, and that the factory fixture doesn't benefit from the fixture specialization done in the register call, we need to override each factory fixture to inject the `fauna_test_client_with_fsl` into each factory and its sub-factories that need the test client. We use `functools.partial` to inject the test client but leave the result as a callable so to the user it has the same API as the regular factory fixture. """def_inner(factory_class, fauna_test_client_paths):
returnfunctools.partial(
factory_class,
**{path: fauna_test_client_with_fslforpathinfauna_test_client_paths},
)
return_inner@pytest.fixturedefaccount_factory(fixup_factory_fixture):
"""Override the default factory fixture with our fixed up one."""returnfixup_factory_fixture(
factory_class=AccountFactory, fauna_test_client_paths=("fauna_test_client",)
)
However, this simply results in the error TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases when calling model_fixture due to it assuming the return value of the factory fixture is always the factory class.
I think ultimately, this would be better solved if there was some way to access the pytest request object within the FactoryClass itself. That way, within the overridden _create classmethod, I could use request.getfixturevalue("fauna_test_client_with_fsl") to retrieve the test client fixture instead of trying to hack it in as a field value.
I'm not sure if this is possible, since I don't know if the factory fixtures and model fixtures are evaluated on every new test function execution, and thus would have the pytest request fixture available. Does anyone know if this is possible?
The text was updated successfully, but these errors were encountered:
I have an existing fixture that will automatically create a test database and return a client attached to that database for a test, and destroy the test database afterwards. I want to use this fixture to build a Django-like model factory, but I'm running into issues with how to inject this fixture's return value into the Factory.
Here's what I've come up with so far:
This is janky, because it only applies the lazy fixture to the model fixture, and not the factory fixture. I attempted to rectify this by overriding the factory fixture like so:
However, this simply results in the error
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
when callingmodel_fixture
due to it assuming the return value of the factory fixture is always the factory class.I think ultimately, this would be better solved if there was some way to access the pytest request object within the FactoryClass itself. That way, within the overridden
_create
classmethod, I could userequest.getfixturevalue("fauna_test_client_with_fsl")
to retrieve the test client fixture instead of trying to hack it in as a field value.I'm not sure if this is possible, since I don't know if the factory fixtures and model fixtures are evaluated on every new test function execution, and thus would have the pytest request fixture available. Does anyone know if this is possible?
The text was updated successfully, but these errors were encountered: