mariano
mariano

Reputation: 1367

Model instance fixtures not persisted on the database

I have a test class with two methods, and want to share a saved model instance between both methods.

My fixtures:

@pytest.fixture(scope='class')
def model_factory():
    class ModelFactory(object):
        def get(self):
            x = Model(email='[email protected]',
                      name='test')
            x.save()
            return x
    return ModelFactory()

@pytest.fixture(scope='class')
def model(model_factory):
    m = model_factory.get()
    return m

My expectation is to receive only the model fixture on (both) my test methods and have it be the same, persisted on the database:

@pytest.mark.django_db
class TestModel(object):

    def test1(self, model):
        assert model.pk is not None
        Model.objects.get(pk=model.pk)  # Works, instance is in the db

    def test2(self, model):
        assert model.pk is not None     # model.pk is the same as in test1
        Model.objects.get(pk=model.pk)  # Fails:
        # *** DoesNotExist: Model matching query does not exist

I've verified using --pdb that at the end of test1, running Model.objects.all() returns the single instance I created. Meanwhile, psql shows no record:

test_db=# select * from model_table;
 id | ··· fields
(0 rows)

Running the Model.objects.all() in pdb at the end of test2 returns an empty list, which is presumably right considering that the table is empty.

  1. Why isn't my model being persisted, while the query still returns an instance anyway?
  2. Why isn't the instance returned by the query in the second test, if my model fixture is marked scope='class' and saved? (This was my original question until I found out saving the model didn't do anything on the database)

Using django 1.6.1, pytest-django 2.9.1, pytest 2.8.5

Thanks

Upvotes: 2

Views: 1603

Answers (3)

Antash
Antash

Reputation: 988

Scope argument is in this case a bit misleading, however if you would write your code like this:

@pytest.fixture(scope='class')
    def model_factory(db, request):
        # body

then you would get an error basically saying that database fixture has to be implemented with 'function' scope.

I would like to add that this is being currently worked on and might be an killing feature in the future ;) github pull request

Upvotes: 0

mariano
mariano

Reputation: 1367

By looking at the postgres log I've found that pytest-django by default does a ROLLBACK after each test to keep things clean (which makes sense, as tests shouldn't depend on state possibly modified by earlier tests).

By decorating the test class with django_db(transaction=True) I could indeed see the data commited at the end of each test from psql, which answers my first question.

Same as before, the test runner ensures no state is kept between tests, which is the answer to my second point.

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599450

Tests must be independent of each other. To ensure this, Django - like most frameworks - clears the db after each test. See the documentation.

Upvotes: 1

Related Questions