django - how to detect test environment (check / determine if tests are being run)

How can I detect whether a view is being called in a test environment (e.g., from manage.py test)?

#pseudo_code
def my_view(request):
    if not request.is_secure() and not TEST_ENVIRONMENT:
        return HttpResponseForbidden()

Solution 1:

Put this in your settings.py:

import sys

TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'

This tests whether the second commandline argument (after ./manage.py) was test. Then you can access this variable from other modules, like so:

from django.conf import settings

if settings.TESTING:
    ...

There are good reasons to do this: suppose you're accessing some backend service, other than Django's models and DB connections. Then you might need to know when to call the production service vs. the test service.

Solution 2:

Create your own TestSuiteRunner subclass and change a setting or do whatever else you need to for the rest of your application. You specify the test runner in your settings:

TEST_RUNNER = 'your.project.MyTestSuiteRunner'

In general, you don't want to do this, but it works if you absolutely need it.

from django.conf import settings
from django.test.simple import DjangoTestSuiteRunner

class MyTestSuiteRunner(DjangoTestSuiteRunner):
    def __init__(self, *args, **kwargs):
        settings.IM_IN_TEST_MODE = True
        super(MyTestSuiteRunner, self).__init__(*args, **kwargs)

Solution 3:

Just look at request.META['SERVER_NAME']

def my_view(request):
    if request.META['SERVER_NAME'] == "testserver":
        print "This is test environment!"

Solution 4:

There's also a way to temporarily overwrite settings in a unit test in Django. This might be a easier/cleaner solution for certain cases.

You can do this inside a test:

with self.settings(MY_SETTING='my_value'):
    # test code

Or add it as a decorator on the test method:

@override_settings(MY_SETTING='my_value')
def test_my_test(self):
    # test code

You can also set the decorator for the whole test case class:

@override_settings(MY_SETTING='my_value')
class MyTestCase(TestCase):
    # test methods

For more info check the Django docs: https://docs.djangoproject.com/en/1.11/topics/testing/tools/#django.test.override_settings

Solution 5:

I think the best approach is to run your tests using their own settings file (i.e. settings/tests.py). That file can look like this (the first line imports settings from a local.py settings file):

from local import *
TEST_MODE = True

Then do ducktyping to check if you are in test mode.

try:
    if settings.TEST_MODE:
        print 'foo'
except AttributeError:
    pass