parent
637e566d05
commit
2d4f1f022e
|
@ -2,6 +2,7 @@
|
|||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import bdb
|
||||
import os
|
||||
import sys
|
||||
from time import time
|
||||
|
||||
|
@ -91,9 +92,11 @@ def show_test_item(item):
|
|||
tw.write(' (fixtures used: {0})'.format(', '.join(used_fixtures)))
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
_update_current_test_var(item, 'setup')
|
||||
item.session._setupstate.prepare(item)
|
||||
|
||||
def pytest_runtest_call(item):
|
||||
_update_current_test_var(item, 'call')
|
||||
try:
|
||||
item.runtest()
|
||||
except Exception:
|
||||
|
@ -107,7 +110,23 @@ def pytest_runtest_call(item):
|
|||
raise
|
||||
|
||||
def pytest_runtest_teardown(item, nextitem):
|
||||
_update_current_test_var(item, 'teardown')
|
||||
item.session._setupstate.teardown_exact(item, nextitem)
|
||||
_update_current_test_var(item, None)
|
||||
|
||||
|
||||
def _update_current_test_var(item, when):
|
||||
"""
|
||||
Update PYTEST_CURRENT_TEST to reflect the current item and stage.
|
||||
|
||||
If ``when`` is None, delete PYTEST_CURRENT_TEST from the environment.
|
||||
"""
|
||||
var_name = 'PYTEST_CURRENT_TEST'
|
||||
if when:
|
||||
os.environ[var_name] = '{0} ({1})'.format(item.nodeid, when)
|
||||
else:
|
||||
os.environ.pop(var_name)
|
||||
|
||||
|
||||
def pytest_report_teststatus(report):
|
||||
if report.when in ("setup", "teardown"):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Introduce the ``PYTEST_CURRENT_TEST`` environment variable that is set with the ``nodeid`` and stage (``setup``, ``call`` and
|
||||
``teardown``) of the test being currently executed. See the `documentation <https://docs.pytest.org/en/latest/example/simple.html#pytest-current-test-environment-variable>`_ for more info.
|
|
@ -761,6 +761,47 @@ and run it::
|
|||
You'll see that the fixture finalizers could use the precise reporting
|
||||
information.
|
||||
|
||||
``PYTEST_CURRENT_TEST`` environment variable
|
||||
--------------------------------------------
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
Sometimes a test session might get stuck and there might be no easy way to figure out
|
||||
which test got stuck, for example if pytest was run in quiet mode (``-q``) or you don't have access to the console
|
||||
output. This is particularly a problem if the problem helps only sporadically, the famous "flaky" kind of tests.
|
||||
|
||||
``pytest`` sets a ``PYTEST_CURRENT_TEST`` environment variable when running tests, which can be inspected
|
||||
by process monitoring utilities or libraries like `psutil <https://pypi.python.org/pypi/psutil>`_ to discover which
|
||||
test got stuck if necessary:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import psutil
|
||||
|
||||
for pid in psutil.pids():
|
||||
environ = psutil.Process(pid).environ()
|
||||
if 'PYTEST_CURRENT_TEST' in environ:
|
||||
print(f'pytest process {pid} running: {environ["PYTEST_CURRENT_TEST"]}')
|
||||
|
||||
During the test session pytest will set ``PYTEST_CURRENT_TEST`` to the current test
|
||||
:ref:`nodeid <nodeids>` and the current stage, which can be ``setup``, ``call``
|
||||
and ``teardown``.
|
||||
|
||||
For example, when running a single test function named ``test_foo`` from ``foo_module.py``,
|
||||
``PYTEST_CURRENT_TEST`` will be set to:
|
||||
|
||||
#. ``foo_module.py::test_foo (setup)``
|
||||
#. ``foo_module.py::test_foo (call)``
|
||||
#. ``foo_module.py::test_foo (teardown)``
|
||||
|
||||
In that order.
|
||||
|
||||
.. note::
|
||||
|
||||
The contents of ``PYTEST_CURRENT_TEST`` is meant to be human readable and the actual format
|
||||
can be changed between releases (even bug fixes) so it shouldn't be relied on for scripting
|
||||
or automation.
|
||||
|
||||
Freezing pytest
|
||||
---------------
|
||||
|
||||
|
|
|
@ -681,6 +681,8 @@ def test_store_except_info_on_eror():
|
|||
"""
|
||||
# Simulate item that raises a specific exception
|
||||
class ItemThatRaises(object):
|
||||
nodeid = 'item_that_raises'
|
||||
|
||||
def runtest(self):
|
||||
raise IndexError('TEST')
|
||||
try:
|
||||
|
@ -693,6 +695,31 @@ def test_store_except_info_on_eror():
|
|||
assert sys.last_traceback
|
||||
|
||||
|
||||
def test_current_test_env_var(testdir, monkeypatch):
|
||||
pytest_current_test_vars = []
|
||||
monkeypatch.setattr(sys, 'pytest_current_test_vars', pytest_current_test_vars, raising=False)
|
||||
testdir.makepyfile('''
|
||||
import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
@pytest.fixture
|
||||
def fix():
|
||||
sys.pytest_current_test_vars.append(('setup', os.environ['PYTEST_CURRENT_TEST']))
|
||||
yield
|
||||
sys.pytest_current_test_vars.append(('teardown', os.environ['PYTEST_CURRENT_TEST']))
|
||||
|
||||
def test(fix):
|
||||
sys.pytest_current_test_vars.append(('call', os.environ['PYTEST_CURRENT_TEST']))
|
||||
''')
|
||||
result = testdir.runpytest_inprocess()
|
||||
assert result.ret == 0
|
||||
test_id = 'test_current_test_env_var.py::test'
|
||||
assert pytest_current_test_vars == [
|
||||
('setup', test_id + ' (setup)'), ('call', test_id + ' (call)'), ('teardown', test_id + ' (teardown)')]
|
||||
assert 'PYTEST_CURRENT_TEST' not in os.environ
|
||||
|
||||
|
||||
class TestReportContents(object):
|
||||
"""
|
||||
Test user-level API of ``TestReport`` objects.
|
||||
|
|
Loading…
Reference in New Issue