public
Last active

See: http://stackoverflow.com/questions/13705328/ -- I was looking for a way to run Selenium tests for a Django app on a staging server hosted on Heroku using a PostgreSQL database. The DjangoTestSuiteRunner creates and destroys the whole database before/after testing, which would not work on Heroku where databases are added via other means (heroku toolbelt, web admin, etc.). To remedy, I created a custom test suite runner which does not create/delete the test database, and rather uses the TEST_DATABASES setting to find the database connection parameters.

  • Download Gist
settings.py
Python
1 2 3 4 5 6 7 8
import dj_database_url
 
TEST_DATABASES = {
'default': dj_database_url.config(env='TEST_DATABASE_URL')
}
 
# replace path below to point to HerokuTestSuiteRunner class
TEST_RUNNER = 'python.path.to.test_suite_runner.HerokuTestSuiteRunner'
test_suite_runner.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
"""
To use this, run:
 
heroku addons:add heroku-postgresql:dev
heroku config:set TEST_DATABASE_URL="postgres://..." # replace with the new HEROKU_POSTGRESQL_<COLOR>_URL
 
Then, make TEST_RUNNER setting a Python path to the HerokuTestSuiteRunner class.
"""
 
import django
from django.test.simple import DjangoTestSuiteRunner
from django.conf import settings
from django.core.management import call_command
from django.db.utils import ConnectionHandler
 
class HerokuTestSuiteRunner(DjangoTestSuiteRunner):
def setup_databases(self, **kwargs):
###
# WARNING: NOT handling 'TEST_MIRROR', 'TEST_DEPENDENCIES'
###
 
# get new connections to test database
test_connections = ConnectionHandler(settings.TEST_DATABASES)
 
for alias in django.db.connections:
test_connection = test_connections[alias]
 
# set django-wide connection to use test connection
django.db.connections[alias] = test_connection
 
# re-initialize database (this "replaces" the CREATE DATABASE which
# cannot be issued on Heroku)
cursor = test_connection.cursor()
cursor.execute('DROP SCHEMA public CASCADE')
cursor.execute('CREATE SCHEMA public')
 
# code below taken from
# django.test.simple.DjangoTestSuiteRunner.setup_databases and
# django.db.backends.creation.create_test_db
 
# make them tables
call_command('syncdb',
verbosity=0,
interactive=False,
database=test_connection.alias,
load_initial_data=False)
 
call_command('flush',
verbosity=0,
interactive=False,
database=test_connection.alias)
 
from django.core.cache import get_cache
from django.core.cache.backends.db import BaseDatabaseCache
for cache_alias in settings.CACHES:
cache = get_cache(cache_alias)
if isinstance(cache, BaseDatabaseCache):
call_command('createcachetable', cache._table,
database=test_connection.alias)
 
def teardown_databases(self, *args, **kwargs):
# NOP
pass

Hi, thank you for your code! I'm getting this error on Heroku:

raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
django.core.exceptions.ImproperlyConfigured: You need to specify NAME in your Django settings file.

Copied your file and added this to settings:

TEST_DATABASES = {
'default': dj_database_url.config(env='TEST_DATABASE_URL')
}

TEST_RUNNER = 'test_tools.test_suite_runner.HerokuTestSuiteRunner'

added a test_tools module with test_suite_runner.py in it.

heroku config shows TEST_DATABASE_URL to the correct db.

Any ideas why?

Nevermind...TEST_DATABASE_URL was improperly configured.

My confusion came from here:

heroku config:set TEST_DATABASE_URL="postgres://..." # replace with the new HEROKU_POSTGRESQL__URL

I added like this:

heroku config:set TEST_DATABASE_URL="postgres://HEROKU_POSTGRESQL_GOLD_URL"

Had to do heroku config

copied the HEROKU_POSTGRESQL_GOLD_URL value and changed it in TEST_DATABASE_URL...worked like a charm

Hi @nitochi -- sorry I didn't see your comment. Your fix is correct.

Were you able to run your tests on Heroku?

Cheers

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.