pytest-factoryboy icon indicating copy to clipboard operation
pytest-factoryboy copied to clipboard

Mark model fixtures with usefixtures('db_session')

Open barraponto opened this issue 3 years ago • 4 comments

Because I'm using pytest-flask-sqlalchemy (see #11), I feel the need to always add the db_session fixture to every test that uses model fixtures from pytest-factoryboy. Particularly, if I try something like:

@pytest.mark.usefixtures("location") # ensures there is one location created.
def test_company_cascades(db_session, user):
    """Test users and locations are deleted when company is deleted."""
    db_session.delete(user.company)
    db_session.commit()

    assert not db_session.query(User).all()
    assert not db_session.query(Location).all()

It fails (sqlalchemy.exc.InvalidRequestError: Object '<User at 0x7fb602180160>' is already attached to session '12' (this is '13')). I can fix it by adding db_session to the usefixtures call:

@pytest.mark.usefixtures("db_session", "location") # ensures there is one location created.
def test_company_cascades(db_session, user):

barraponto avatar Oct 28 '20 13:10 barraponto

What I'm looking is for something like register(CompanyFactory, usefixtures='db_session') or maybe a setting somewhere in conftest.py

barraponto avatar Oct 28 '20 13:10 barraponto

You should configure @pytest.fixture(autouse=True) on your db_session fixture. Then it will apply to all tests on the conftest.py (or all if it is on your parent tests folder).

@pytest.fixture(scope='function', autouse=True)
def session(db):
    """Creates a new database session for a test."""
    ...
    yield session
    ...

Another option, could be to define it on a class with several tests:

@@pytest.mark.usefixtures("db_session", "location") # ensures there is one location created.
class TestGroupUsingSession:
    def test1(self):
        ...
    def test2(self):
        ...

More info here: pytest-fixture.

However, not sure if this request is something really needed for pytest-factoryboy. Session used for writing into the database is defined at your factories using factory-boy methods. See Using factory_boy with ORMs. Which is already inherited in pytest-factoryboy.

BorjaEst avatar Apr 22 '21 06:04 BorjaEst

@BorjaEst This would cause any test to create the database (which can be an expensive operation) even if the specific test actually doesn't need it.

mrcljx avatar Apr 22 '21 13:04 mrcljx

@sirlantis I see the point, however, to link the session to the registration... would it be safe if the API you are testing also changes the db state? What if you want to share an instance between tests? Although indeed, it might be a nice feature, there are other ways to easily pass it. So I wouldn't close the issue oppen so maybe the developers work on it.

To speed up, instead of creating the db at each test, I would just create a fixture wich delivers a new session and rollback when the test is finished, that would be much more efficient than creating a new database every test!

As I mentioned, you can also scope your fixture to a folder where you place only the tests that need that session, or you use classes.

BorjaEst avatar Apr 22 '21 15:04 BorjaEst

Closing this as a 2 years have passed. Feel free to ask it to be reopened if it's still an issue.

youtux avatar Jul 23 '23 20:07 youtux