How to run a method before all tests in all classes?
Solution 1
You might want to use a session-scoped "autouse" fixture:
# content of conftest.py or a tests file (e.g. in your tests or root directory)
@pytest.fixture(scope="session", autouse=True)
def do_something(request):
# prepare something ahead of all tests
request.addfinalizer(finalizer_function)
This will run ahead of all tests. The finalizer will be called after the last test finished.
Solution 2
Using session fixture as suggested by hpk42 is great solution for many cases, but fixture will run only after all tests are collected.
Here are two more solutions:
conftest hooks
Write a pytest_configure
or pytest_sessionstart
hook in your conftest.py
file:
# content of conftest.py
def pytest_configure(config):
"""
Allows plugins and conftest files to perform initial configuration.
This hook is called for every plugin and initial conftest
file after command line options have been parsed.
"""
def pytest_sessionstart(session):
"""
Called after the Session object has been created and
before performing collection and entering the run test loop.
"""
def pytest_sessionfinish(session, exitstatus):
"""
Called after whole test run finished, right before
returning the exit status to the system.
"""
def pytest_unconfigure(config):
"""
called before test process is exited.
"""
pytest plugin
Create a pytest plugin with pytest_configure
and pytest_unconfigure
hooks.
Enable your plugin in conftest.py
:
# content of conftest.py
pytest_plugins = [
'plugins.example_plugin',
]
# content of plugins/example_plugin.py
def pytest_configure(config):
pass
def pytest_unconfigure(config):
pass
Solution 3
Starting from version 2.10 there is a cleaner way to tear down the fixture as well as defining its scope. So you may use this syntax:
@pytest.fixture(scope="module", autouse=True)
def my_fixture():
print ('INITIALIZATION')
yield param
print ('TEAR DOWN')
The autouse parameter: From documentation:
Here is how autouse fixtures work in other scopes:
autouse fixtures obey the scope= keyword-argument: if an autouse fixture has scope='session' it will only be run once, no matter where it is defined. scope='class' means it will be run once per class, etc.
if an autouse fixture is defined in a test module, all its test functions automatically use it.
if an autouse fixture is defined in a conftest.py file then all tests in all test modules below its directory will invoke the fixture.
...
The "request" parameter: Note that the "request" parameter is not necessary for your purpose although you might want to use it for other purposes. From documentation:
"Fixture function can accept the request object to introspect the “requesting” test function, class or module context.."
Solution 4
Try to use pytest_sessionstart(session)
in conftest.py
Example:
# project/tests/conftest.py
def pytest_sessionstart(session):
print('BEFORE')
# project/tests/tests_example/test_sessionstart.py
import pytest
@pytest.fixture(scope='module', autouse=True)
def fixture():
print('FIXTURE')
def test_sessonstart():
print('TEST')
Log:
BEFORE
============================================================================ test session starts =============================================================================
platform darwin -- Python 3.7.0, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
cachedir: .pytest_cache
rootdir: /Users/user/Documents/test, inifile: pytest.ini
plugins: allure-pytest-2.8.12, env-0.6.2
collected 1 item
tests/6.1/test_sessionstart.py::test_sessonstart FIXTURE
TEST
PASSED
Read more here: https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_sessionstart
Hugh Perkins
Machine learning engineer. Wrote DeepCL, https://github.com/hughperkins/DeepCL, and a bunch of other GPU/OpenCL things.
Updated on July 05, 2022Comments
-
Hugh Perkins almost 2 years
I'm writing selenium tests, with a set of classes, each class containing several tests. Each class currently opens and then closes Firefox, which has two consequences:
- super slow, opening firefox takes longer than running the test in a class...
- crashes, because after firefox has been closed, trying to reopen it really quickly, from selenium, results in an 'Error 54'
I could solve the error 54, probably, by adding a sleep, but it would still be super slow.
So, what I'd like to do is reuse the same Firefox instances across all test classes. Which means I need to run a method before all test classes, and another method after all test classes. So, 'setup_class' and 'teardown_class' are not sufficient.
-
Math is Hard over 5 yearsThis is the best answer. Put a
conftest.py
in the same directory as your other tests that you wish to run with the samepytest_sessionstart
andpytest_sessionfinish
routines. -
lalatnayak about 5 yearsI think this does not work if the tests are spread across multiple files
-
machazthegamer over 3 yearsThis won't work if i want to include a function scoped fixture to be used in this function
-
Scott McAllister almost 3 yearsThis absolutely works when tests are split across many files.
-
Asclepius over 2 yearsWill this run before each test or a total of once before testing?
-
afaulconbridge about 2 yearsThis will be called once for each worker, if running tests in parallel. That might be what you want, or it might not be (e.g. a shared resource such as Firefox or a database).