Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pytest not creating test DB #131

Closed
maryokhin opened this issue Jul 13, 2014 · 7 comments
Closed

pytest not creating test DB #131

maryokhin opened this issue Jul 13, 2014 · 7 comments

Comments

@maryokhin
Copy link

There's a big chance that I'm not doing something right, because I am very new to pytest, but basically I am using the exact same test DB settings as for unittest, but pytest is giving me django.db.utils.OperationalError: FATAL: database "database" does not exist https://gist.github.com/maryokhin/0749d31ef9b273b13352. Got tired of banging my head, so wanted to ask, maybe someone knows what's up.

As a subquestion, when using pytest or pytest-django decorators, PyCharm always warns of unresolved references, is it because under the hood they use some dynamic stuff it can't detect?

@pelme
Copy link
Member

pelme commented Jul 14, 2014

The exception stems from setup_module(), which is not really supported to create database objects in pytest-django. pytest-django uses the pytest fixture system to configure the database.

To create an object in the database, use something like:

@pytest.fixture
def myobjects(db):
    channel = Channel.objects.create(name='test')

You can then use pytestmark = pytest.mark.usefixtures('myobjects') in a test module to have it invoked for all tests. If you want to use it for all tests in your test suite, place use @pytest.fixture(autouse=True) and put it into a file called conftest.py in your project root.

See
http://pytest.org/latest/plugins.html for more information on conftest
#53 for more information about setup_module
http://pytest-django.readthedocs.org/en/latest/helpers.html#db for more information about the db fixture

What decorators do you mean? Can you provide an example that pycharm warns on?

@maryokhin
Copy link
Author

Thank you for your detailed response.
Basically what I'm trying to do is the simplest use-case.

Create a bunch of objects on module level:

@pytest.fixture
def myobjects(db):
    channel1 = Channel.objects.create(name='test')
    channel2 = Channel.objects.create(name='test')
    channel3 = Channel.objects.create(name='test')

Tell each test in the module to use them:

pytestmark = pytest.mark.usefixtures('myobjects')

Or one test/class in a module:

@pytest.mark.usefixtures('myobjects')

And then be able to use these objects in tests like:

def test_something();
     assert myobjects.channel1.name = 'test'
     assert myobjects.channel2.name = 'test'
     assert myobjects.channel3.name = 'test'

I am guessing I should return a class from the fixture then, but it kind of feels a bit weird. Do people just insantiate the test objects inside each test? To me it seems unnecessary overhead, so I am trying to move the ones I can to the module level.

The way I had it in unittest (not really smart, but it worked):

def setUpModule():
    global user1, user2, user3
    user1 = UserFactory()
    user2 = UserFactory()
    user3 = UserFactory()

def tearDownModule():
    User.objects.all().delete()

@maryokhin
Copy link
Author

It's not really important, but PyCharm is funky will all the pytest related stuff.
2014-07-14 14 41 18

@pelme
Copy link
Member

pelme commented Jul 14, 2014

It is currently not possible to do that at the module level, but there is plans to allow caching on the module level in the future. It is possible with pytest fixtures to cache things on the module level, but it does currently not interact with Django's transactions in a sane way.

I personally very rarely have the same test data in two different tests, and rather use factory boy to construct exactly the database state I need for each test. It makes the tests much easier to follow and usually faster since you need fewer objects.

To avoid wrapping them in classes, you can access the fixture as an argument:

@pytest.fixture
def channel1(db):
    return Channel.objects.create(name='test')

@pytest.fixture
def channel2(db):
    return Channel.objects.create(name='test')

def mytest(channel1, channel2):
    assert channel1.name == 'test'
    assert channel2.name == 'test'

@pelme
Copy link
Member

pelme commented Jul 14, 2014

You probably need to add an exception for PyCharm to avoid looking into pytest. pytest does a lot of meta-things internally and is generally hard to introspect, I would say. You should probably open a bug for PyCharm and/or pytest for this issue.

@maryokhin
Copy link
Author

Ok, thank you again, it would taken me much more time to stumble upon the same info. I guess I'll do the same thing and create factory instances instances in each test for now, and worry about it if it get's slow in the future.

@pelme
Copy link
Member

pelme commented Jul 14, 2014

I gave a talk last year at EuroPython where I discuss this problem. Here is the part on model test data:
http://youtu.be/aUf8Fkb7TaY?t=32m55s

(You might enjoy the full talk if you are new to pytest-django, too)

@pelme pelme closed this as completed Jul 14, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants