Py.test funcargs and Django
Holger Krekel just released the 1.0 version of py.test. Py.test is a functional and unit testing tool that cuts out a lot of the annoying boilerplate found in the unittest module included in the Python standard library.
I do a lot of Django coding. Django has a built-in test engine based on unittest. Its annoying, but it does a few things (such as capturing e-mails and creating a test database) automatically so I’ve tended to use it rather than setting up py.test to take care of these things. Today I decided I’d rather use py.test for my latest project. Turns out its not that complicated:
# there are better ways to do these first three lines import os, sys sys.path.append('.') os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' from django.conf import settings from django.test.client import Client from django.test.utils import setup_test_environment, teardown_test_environment from django.core.management import call_command def pytest_funcarg__django_client(request): old_name = settings.DATABASE_NAME def setup(): setup_test_environment() settings.DEBUG = False from django.db import connection connection.creation.create_test_db(1, True) return Client() def teardown(client): teardown_test_environment() from django.db import connection connection.creation.destroy_test_db(old_name, 1) return request.cached_setup(setup, teardown, "session") def pytest_funcarg__client(request): def setup(): return request.getfuncargvalue('django_client') def teardown(client): call_command('flush', verbosity=0, interactive=False) mail.outbox = [] return request.cached_setup(setup, teardown, "function")
Put that in your conftest.py and you can write tests like this:
def test_something(client): response = client.post('/some_url', {'someparam': 'somevalue'}) assert "somestring" in response.content # Other assertions...
This uses the innovative py.test ‘funcarg’ mechanism to create a test database when testing starts, and refer to that database throughout the test run. The ‘django_client’ funcarg sets up a database when the session starts and deletes it when it finishes. The ‘client’ funcarg creates a similar client, but also resets the database after each test is run to ensure there are no interaction effects between tests.
I haven’t fully tested it yet, but its nice to know I can get the most useful django test functionality so cheaply in py.test.
