Is this the correct use of conftest.py?
Yes it. Lamps are a potential and common use for conftest.py . The instruments you define will be available to all tests in your test suite. However, defining devices in the root conftest.py may be useless, and this will slow down testing if such devices are not used by all tests.
Does it have another use?
Yes it is.
Fixtures : Define fixtures for the static data used by tests. This data may be available for all tests in the set, unless otherwise specified. This can be both data and module helpers, which will be passed to all tests.
Download external plugins : conftest.py used to import external plugins or modules. Having defined the following global variable, pytest will load the module and make it available for testing it. Plugins are usually files defined in your project or other modules that may be needed in your tests. You can also download a set of predefined plugins as described here .
pytest_plugins = "someapp.someplugin"
Hooks : You can specify hooks, such as configuration and dismantling methods, and much more to improve your tests. For a set of available hooks, read here . Example:
def pytest_runtest_setup(item): """ called before ''pytest_runtest_call(item). """
Checking the root path : this is a bit of a hidden feature. conftest.py defining conftest.py in your root path, you will be able to pytest recognize your application modules without specifying PYTHONPATH . In the background, py.test modifies your sys.path , including all submodules found in the root path.
Can I have more than one conftest.py file?
Yes you can, and it is highly recommended if your test framework is somewhat complex. conftest.py files have a directory scope. Therefore, creating targeted devices and assistants is good practice.
When do I want to do this? Examples will be appreciated.
Several cases may come up:
Creating a set of tools or hooks for a specific group of tests.
root / mod /conftest.py
def pytest_runtest_setup(item): print("I am mod")
Loading a set of fixtures for some tests, but not for others.
root / mod /conftest.py
@pytest.fixture() def fixture(): return "some stuff"
root / mod 2 / conftest.py
@pytest.fixture() def fixture(): return "some other stuff"
root / mod 2 / test.py
def test(fixture): print(fixture)
Prints "some other stuff."
Overriding hooks inherited from the root conftest.py .
root / mod /conftest.py
def pytest_runtest_setup(item): print("I am mod")
root / conftest.py
def pytest_runtest_setup(item): print("I am root")
When running any test inside root/mod , root/mod only "I am mod".
You can read more about conftest.py here .
EDIT:
What if I need simple old helper functions to call from several tests in different modules - will they be available to me if I put them in the conftest.py file? Or should I just put them in the helpers.py module and import and use in my test modules?
You can use conftest.py to define your helpers. However, you should follow your usual practice. Helpers can be used as fixtures, at least in pytest . For example, in my tests, I have a redis helper helper that I add to my tests this way.
root / helper /Redis/redis.py
@pytest.fixture def mock_redis(): return MockRedis()
root / tests / stuff /conftest.py
pytest_plugin="helper.redis.redis"
root / tests / stuff /test.py
def test(mock_redis): print(mock_redis.get('stuff'))
This will be a test module that you can freely import into your tests. Note that you could potentially name redis.py as conftest.py if your redis module contains more tests. However, this practice is not recommended due to ambiguity.
If you want to use conftest.py , you can simply put this helper in the root conftest.py and conftest.py it if necessary.
root / tests / conftest.py
@pytest.fixture def mock_redis(): return MockRedis()
root / tests / stuff /test.py
def test(mock_redis): print(mock_redis.get(stuff))
Another thing you can do is write an installable plugin. In this case, your assistant can be written anywhere, but it needs to determine the entry point that will be installed in your and other potential test environments. Watch this .
If you don't want to use latches, you can of course define a simple helper and just use the plain old import wherever you need to.
root / tests / helper /redis.py
class MockRedis():
root / tests / stuff /test.py
from helper.redis import MockRedis def test(): print(MockRedis().get(stuff))
However, there may be problems with the path, because the module is not in the child folder of the test. You should be able to overcome this (not verified) by adding __init__.py to your assistant
root / tests / helper / __ init__.py
from .redis import MockRedis
Or simply by adding a helper module to your PYTHONPATH .