Pytest-django: Provide a way to detect if Django is running tests

Created on 6 May 2016  ·  9Comments  ·  Source: pytest-dev/pytest-django

It'd be nice to do something like:

if settings.TESTING:
    print("py.test is being ran")

Most helpful comment

"pytest" in sys.modules?

All 9 comments

"pytest" in sys.modules?

You can add a setting yourself with a separate settings file for tests

I think the approaches suggested by @blueyed and @adamchainz should be sufficient if this is needed. Generally, changing the way your code works by introspecting whether or not the code is called from tests is not recommended. If this were to be done, it could be done in a general pytest way (it is not really specific to pytest-django). Thanks for the suggestion, feel free to reopen this issue if you have additional information in this issue!

Relevant example from the pytest docs Detect if running from within a pytest run:

# content of conftest.py

def pytest_configure(config):
    import sys
    sys._called_from_test = True

def pytest_unconfigure(config):
    import sys
    del sys._called_from_test

The problem is that pytest_configure is run after settings.py. Is there a way to run this code before settings.py?

@axil
What is wrong with using 'pytest' in sys.modules?

Hmm, yes, got it working, though it looks a bit hacky for me.

Another quick and dirty way to check this in settings.py is

TESTING = os.path.basename(sys.argv[0]) in ('pytest', 'py.test')

@axil
What is wrong with using 'pytest' in sys.modules?

The fact the pytest is imported does not mean that pytest is running and the code is invoked from a test. Basically, one my import pytest for something else. Also pytest is importing pytest even if it just show a CLI help: pytest --help

Here is very valid use case:
I have django setting configurable with local files and variables where put various credentials and other local dev env configuration. But I want my unittests never use this credentials or specific settings to not accidentally use them on some real system (if improperly mocked) or pass/fail on local dev env configuration. Therefore I want these local settings excluded when ran with pytest.

I have something like:

import os
import os.path
import sys

from split_settings.tools import include, optional


def is_pytest_running():
    return (os.getenv('PYTEST_RUNNING') == 'true' or
            os.path.basename(sys.argv[0]) in ('pytest', 'py.test'))


ENVVAR_SETTINGS_PREFIX = 'MV_SERVER_'

local_settings_path = os.getenv(f'{ENVVAR_SETTINGS_PREFIX}SETTINGS', '../../../local/settings.py')

includes = [
    'base.py',
    'logging.py',
    'custom.py',
]

if not is_pytest_running():
    includes.append(optional(local_settings_path))
    includes.append('envvars.py')

include(*includes)

Using os.getenv('PYTEST_RUNNING') == 'true' is more or less clean way of doing it, but the issue is with setting this variable. Setting it in conftest.py does not work because pytest-django imports settings before conftest.py executed. Setting it in commandline when running pytest is inconvenient and also defeats the purpose: if someone forgets to set it then real credentials will be used from local dev env configuration.

os.path.basename(sys.argv[0]) in ('pytest', 'py.test')

I had to change it to os.path.basename(os.path.dirname(sys.argv[0])) in ('pytest', 'py.test') since sys.argv[0] was coming out as /home/project/venv/lib/python3.8/site-packages/pytest/__main__.py.

Was this page helpful?
0 / 5 - 0 ratings