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

Provide a way to detect if Django is running tests #333

Closed
santiagobasulto opened this issue May 5, 2016 · 11 comments
Closed

Provide a way to detect if Django is running tests #333

santiagobasulto opened this issue May 5, 2016 · 11 comments

Comments

@santiagobasulto
Copy link

It'd be nice to do something like:

if settings.TESTING:
    print("py.test is being ran")
@blueyed
Copy link
Contributor

blueyed commented May 12, 2016

"pytest" in sys.modules?

@adamchainz
Copy link
Member

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

@pelme
Copy link
Member

pelme commented Jun 20, 2016

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!

@pelme pelme closed this as completed Jun 20, 2016
@axil
Copy link
Contributor

axil commented May 18, 2017

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?

@blueyed
Copy link
Contributor

blueyed commented May 18, 2017

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

@axil
Copy link
Contributor

axil commented May 18, 2017

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')

@dmugtasimov
Copy link

@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

@dmugtasimov
Copy link

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.

@samkit-jain
Copy link

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.

@Bobronium
Copy link

Bobronium commented Sep 29, 2021

I find all of the solutions above a bit fragile. They are easily broken when running tests from PyCharm, for example, where executable in sys.args is:
sys.argv content

While we can account for this edge case, we certainly never can be sure that this hack will work with other edge cases.

"pytest" in sys.modules is even more fragile for the reasons explained above.

Any solution that involve conftest.py, including the one from pytest docs, won't work if you need to know if tests are running in django settings module, because the django settings module is executed even before conftest.py is read.

Setting env variable like PYTEST_RUNNING is fragile and might be simply annoying, because it requires additional input from developer.

@pelme, I agree with the point that it's mostly not recommended to change the code behaviour based on whether tests are running or not, but as you can see, there's still a demand for it.

Therefore, I thing this library should provide built-in consistent indicator that tests are running.

@dheerajck
Copy link

This might be over engineered but I think this works better and helps to avoid one of the edge case with "pytest" in sys.modules

import os
import inspect
import sys

# List of pytest related files
pytest_related_files = (
    os.path.join('_pytest', 'python_path.py'),
    os.path.join('_pytest', 'logging.py'),
    os.path.join('_pytest', 'main.py'),
    os.path.join('_pytest', 'runner.py'),
    os.path.join('_pytest', 'config', '__init__.py'),
    os.path.join('_pytest', 'debugging.py')
)

# Check if any of the pytest related files are in the current stack
is_pytest_in_stack = any(frame.filename.endswith(pytest_related_files) for frame in inspect.stack())

# Check if a pytest is currently running
is_pytest_running = os.environ.get("PYTEST_CURRENT_TEST")

# Check if pytest module is imported
# We probably dont need to use this as, if one of the other two condition is True, this should be True
is_pytest_imported = "pytest" in sys.modules 

if is_pytest_imported and (is_pytest_in_stack or is_pytest_running):
    print(True)
else:
    print(False)

Do let me know if theres a case where this will not work

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

9 participants