refine and document conftest loading and handling.
--HG-- branch : trunk
This commit is contained in:
parent
f3fb91e296
commit
9925ac883e
|
@ -15,38 +15,6 @@ You can see command line options by running::
|
||||||
This will display all available command line options
|
This will display all available command line options
|
||||||
in your specific environment.
|
in your specific environment.
|
||||||
|
|
||||||
.. _`project-specific test configuration`:
|
|
||||||
.. _`collect_ignore`:
|
|
||||||
|
|
||||||
conftest.py: project specific hooks and configuration
|
|
||||||
--------------------------------------------------------
|
|
||||||
|
|
||||||
A unique feature of py.test are its ``conftest.py`` files which
|
|
||||||
allow to:
|
|
||||||
|
|
||||||
* `set option defaults`_
|
|
||||||
|
|
||||||
or set particular variables to influence the testing process:
|
|
||||||
|
|
||||||
* ``pytest_plugins``: list of named plugins to load
|
|
||||||
|
|
||||||
* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file
|
|
||||||
|
|
||||||
* ``rsyncdirs``: list of to-be-rsynced directories for distributed
|
|
||||||
testing, relative to the containing ``conftest.py`` file.
|
|
||||||
|
|
||||||
You may put a conftest.py files in your project root directory or into
|
|
||||||
your package directory if you want to add project-specific test options.
|
|
||||||
|
|
||||||
``py.test`` loads all ``conftest.py`` files upwards from the command
|
|
||||||
line file arguments. It usually looks up configuration values
|
|
||||||
right-to-left, i.e. the closer conftest files will be checked first.
|
|
||||||
This means you can have a ``conftest.py`` in your very home directory to
|
|
||||||
have some global configuration values.
|
|
||||||
|
|
||||||
.. _`specify funcargs`: funcargs.html#application-setup-tutorial-example
|
|
||||||
|
|
||||||
.. _`set option defaults`:
|
|
||||||
|
|
||||||
setting persistent option defaults
|
setting persistent option defaults
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
@ -57,13 +25,13 @@ py.test will lookup option values in this order:
|
||||||
* conftest.py files
|
* conftest.py files
|
||||||
* environment variables
|
* environment variables
|
||||||
|
|
||||||
To find out about the particular switches and type::
|
To get an overview on existing names and settings type::
|
||||||
|
|
||||||
py.test --help-config
|
py.test --help-config
|
||||||
|
|
||||||
This will print information about all options in your
|
This will print information about all available options
|
||||||
environment, including your local plugins.
|
in your environment, including your local plugins and
|
||||||
|
command line options.
|
||||||
|
|
||||||
.. _`function arguments`: funcargs.html
|
.. _`function arguments`: funcargs.html
|
||||||
.. _`extensions`:
|
.. _`extensions`:
|
||||||
|
@ -73,26 +41,51 @@ Plugin basics and project configuration
|
||||||
|
|
||||||
.. _`local plugin`:
|
.. _`local plugin`:
|
||||||
|
|
||||||
project specific "local" or named "global" plugins
|
py.test implements all aspects of its functionality by calling `well specified
|
||||||
|
hooks`_. Hook functions are discovered in :file:`conftest.py` files or in
|
||||||
|
`named plugins`_. :file:`conftest.py` files are useful for keeping test
|
||||||
|
extensions and customizations close to test code.
|
||||||
|
|
||||||
|
local conftest.py plugins
|
||||||
--------------------------------------------------------------
|
--------------------------------------------------------------
|
||||||
|
|
||||||
py.test implements much of its functionality by calling `well specified
|
local `conftest.py` plugins are usually automatically loaded and
|
||||||
hooks`_. Python modules which contain such hook functions are called
|
registered but its contained hooks are only called when collecting or
|
||||||
plugins. Hook functions are discovered in ``conftest.py`` files or in
|
running tests in files or directories next to or below the ``conftest.py``
|
||||||
`named plugins`_. ``conftest.py`` files are sometimes called
|
file. Assume the following layout and content of files::
|
||||||
"anonymous" or conftest plugins. They are useful for keeping test
|
|
||||||
extensions close to your application. Named plugins are normal python
|
a/conftest.py:
|
||||||
modules or packages that can be distributed separately. Named plugins
|
def pytest_runtest_setup(item):
|
||||||
need to follow a naming pattern; they have an all lowercase ``pytest_``
|
print ("setting up", item)
|
||||||
prefixed name. While conftest plugins are discovered automatically,
|
|
||||||
named plugins must be explicitely specified.
|
a/test_in_subdir.py:
|
||||||
|
def test_sub():
|
||||||
|
pass
|
||||||
|
|
||||||
|
test_flat.py:
|
||||||
|
def test_flat():
|
||||||
|
pass
|
||||||
|
|
||||||
|
Here is how you might run it::
|
||||||
|
|
||||||
|
py.test test_flat.py # will not show "setting up"
|
||||||
|
py.test a/test_sub.py # will show "setting up"
|
||||||
|
|
||||||
|
``py.test`` loads all ``conftest.py`` files upwards from the command
|
||||||
|
line file arguments. It usually looks up configuration values or hooks
|
||||||
|
right-to-left, i.e. the closer conftest files are checked before
|
||||||
|
the further away ones. This means you can have a ``conftest.py``
|
||||||
|
in your home directory to provide global configuration values.
|
||||||
|
|
||||||
|
.. Note::
|
||||||
|
if you have ``conftest.py`` files which do not reside in a
|
||||||
|
python package directory (one containing an ``__init__.py``) then
|
||||||
|
"import conftest" will be ambigous and should be avoided. **If you
|
||||||
|
want to import anything from a ``conftest.py`` file it is better
|
||||||
|
to put it inside a package to disambiguate.
|
||||||
|
|
||||||
.. _`named plugins`: plugin/index.html
|
.. _`named plugins`: plugin/index.html
|
||||||
|
|
||||||
.. _`tool startup`:
|
|
||||||
.. _`loaded at tool startup`:
|
|
||||||
.. _`test tool starts up`:
|
|
||||||
|
|
||||||
Plugin discovery at tool startup
|
Plugin discovery at tool startup
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
|
@ -106,10 +99,10 @@ py.test loads plugin modules at tool startup in the following way:
|
||||||
* by pre-scanning the command line for the ``-p name`` option
|
* by pre-scanning the command line for the ``-p name`` option
|
||||||
and loading the specified plugin before actual command line parsing.
|
and loading the specified plugin before actual command line parsing.
|
||||||
|
|
||||||
* by loading all `conftest.py plugin`_ files as inferred by the command line
|
* by loading all :file:`conftest.py` files as inferred by the command line
|
||||||
invocation (test files and all of its parent directories).
|
invocation (test files and all of its *parent* directories).
|
||||||
Note that ``conftest.py`` files from sub directories are loaded
|
Note that ``conftest.py`` files from *sub* directories are by default
|
||||||
during test collection and not at tool startup.
|
not loaded at tool startup.
|
||||||
|
|
||||||
* by recursively loading all plugins specified by the
|
* by recursively loading all plugins specified by the
|
||||||
``pytest_plugins`` variable in a ``conftest.py`` file
|
``pytest_plugins`` variable in a ``conftest.py`` file
|
||||||
|
@ -132,8 +125,8 @@ must be lowercase.
|
||||||
Writing per-project plugins (conftest.py)
|
Writing per-project plugins (conftest.py)
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
|
||||||
The purpose of ``conftest.py`` files is to allow `project-specific
|
The purpose of :file:`conftest.py` files is to allow project-specific
|
||||||
test configuration`_. They thus make for a good place to implement
|
test customization. They thus make for a good place to implement
|
||||||
project-specific test related features through hooks. For example you may
|
project-specific test related features through hooks. For example you may
|
||||||
set the `collect_ignore`_ variable depending on a command line option
|
set the `collect_ignore`_ variable depending on a command line option
|
||||||
by defining the following hook in a ``conftest.py`` file::
|
by defining the following hook in a ``conftest.py`` file::
|
||||||
|
@ -147,6 +140,7 @@ by defining the following hook in a ``conftest.py`` file::
|
||||||
collect_ignore[:] = []
|
collect_ignore[:] = []
|
||||||
|
|
||||||
.. _`setuptools entry points`:
|
.. _`setuptools entry points`:
|
||||||
|
.. _registered:
|
||||||
|
|
||||||
Writing setuptools-registered plugins
|
Writing setuptools-registered plugins
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
@ -350,3 +344,30 @@ Reference of important objects involved in hooks
|
||||||
.. autoclass:: pytest.plugin.runner.TestReport
|
.. autoclass:: pytest.plugin.runner.TestReport
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
conftest.py configuration files
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
conftest.py reference docs
|
||||||
|
|
||||||
|
A unique feature of py.test are its ``conftest.py`` files which allow
|
||||||
|
project and directory specific customizations to testing.
|
||||||
|
|
||||||
|
* `set option defaults`_
|
||||||
|
|
||||||
|
or set particular variables to influence the testing process:
|
||||||
|
|
||||||
|
* ``pytest_plugins``: list of named plugins to load
|
||||||
|
|
||||||
|
* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file
|
||||||
|
|
||||||
|
* ``rsyncdirs``: list of to-be-rsynced directories for distributed
|
||||||
|
testing, relative to the containing ``conftest.py`` file.
|
||||||
|
|
||||||
|
You may put a conftest.py files in your project root directory or into
|
||||||
|
your package directory if you want to add project-specific test options.
|
||||||
|
|
||||||
|
|
||||||
|
.. _`specify funcargs`: funcargs.html#application-setup-tutorial-example
|
||||||
|
|
||||||
|
.. _`set option defaults`:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import os
|
import sys, os
|
||||||
from pytest._core import PluginManager
|
from pytest._core import PluginManager
|
||||||
|
|
||||||
def pytest_cmdline_parse(pluginmanager, args):
|
def pytest_cmdline_parse(pluginmanager, args):
|
||||||
|
@ -194,14 +194,10 @@ class Conftest(object):
|
||||||
try:
|
try:
|
||||||
return self._conftestpath2mod[conftestpath]
|
return self._conftestpath2mod[conftestpath]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if not conftestpath.dirpath('__init__.py').check(file=1):
|
pkgpath = conftestpath.pypkgpath()
|
||||||
# HACK: we don't want any "globally" imported conftest.py,
|
if pkgpath is None:
|
||||||
# prone to conflicts and subtle problems
|
_ensure_removed_sysmodule(conftestpath.purebasename)
|
||||||
modname = str(conftestpath).replace('.', conftestpath.sep)
|
self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport()
|
||||||
mod = conftestpath.pyimport(modname=modname)
|
|
||||||
else:
|
|
||||||
mod = conftestpath.pyimport()
|
|
||||||
self._conftestpath2mod[conftestpath] = mod
|
|
||||||
dirpath = conftestpath.dirpath()
|
dirpath = conftestpath.dirpath()
|
||||||
if dirpath in self._path2confmods:
|
if dirpath in self._path2confmods:
|
||||||
for path, mods in self._path2confmods.items():
|
for path, mods in self._path2confmods.items():
|
||||||
|
@ -216,6 +212,11 @@ class Conftest(object):
|
||||||
self._onimport(mod)
|
self._onimport(mod)
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
def _ensure_removed_sysmodule(modname):
|
||||||
|
try:
|
||||||
|
del sys.modules[modname]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
class CmdOptions(object):
|
class CmdOptions(object):
|
||||||
""" holds cmdline options as attributes."""
|
""" holds cmdline options as attributes."""
|
||||||
|
|
|
@ -106,6 +106,27 @@ def test_doubledash_not_considered(testdir):
|
||||||
l = conftest.getconftestmodules(None)
|
l = conftest.getconftestmodules(None)
|
||||||
assert len(l) == 0
|
assert len(l) == 0
|
||||||
|
|
||||||
|
def test_conftest_global_import(testdir):
|
||||||
|
testdir.makeconftest("x=3")
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import py
|
||||||
|
from pytest.plugin.config import Conftest
|
||||||
|
conf = Conftest()
|
||||||
|
mod = conf.importconftest(py.path.local("conftest.py"))
|
||||||
|
assert mod.x == 3
|
||||||
|
import conftest
|
||||||
|
assert conftest is mod, (conftest, mod)
|
||||||
|
subconf = py.path.local().ensure("sub", "conftest.py")
|
||||||
|
subconf.write("y=4")
|
||||||
|
mod2 = conf.importconftest(subconf)
|
||||||
|
assert mod != mod2
|
||||||
|
assert mod2.y == 4
|
||||||
|
import conftest
|
||||||
|
assert conftest is mod2, (conftest, mod)
|
||||||
|
""")
|
||||||
|
res = testdir.runpython(p)
|
||||||
|
assert res.ret == 0
|
||||||
|
|
||||||
def test_conftestcutdir(testdir):
|
def test_conftestcutdir(testdir):
|
||||||
conf = testdir.makeconftest("")
|
conf = testdir.makeconftest("")
|
||||||
p = testdir.mkdir("x")
|
p = testdir.mkdir("x")
|
||||||
|
|
Loading…
Reference in New Issue