1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
|
.. _plugins:
Working with plugins and conftest files
=============================================
py.test implements all aspects of configuration, collection, running and reporting by calling `well specified hooks`_. Virtually any Python module can be registered as a plugin. It can implement any number of hook functions (usually two or three) which all have a ``pytest_`` prefix, making hook functions easy to distinguish and find. There are three basic locations types:
* `builtin plugins`_: loaded from py.test's own ``pytest/plugin`` directory.
* `external plugins`_: modules discovered through `setuptools entry points`_
* `conftest.py plugins`_: modules auto-discovered in test directories
.. _`pytest/plugin`: http://bitbucket.org/hpk42/pytest/src/tip/pytest/plugin/
.. _`conftest.py plugins`:
.. _`conftest.py`:
.. _`localplugin`:
.. _`conftest`:
conftest.py: local per-directory plugins
--------------------------------------------------------------
local ``conftest.py`` plugins contain directory-specific hook
implementations. Session and test running activities will
invoke all hooks defined in ``conftest.py`` files closer to the
root of the filesystem. Example: Assume the following layout
and content of files::
a/conftest.py:
def pytest_runtest_setup(item):
# called for running each test in 'a' directory
print ("setting up", item)
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"
.. Note::
If you have ``conftest.py`` files which do not reside in a
python package directory (i.e. one containing an ``__init__.py``) then
"import conftest" can be ambiguous because there might be other
``conftest.py`` files as well on your PYTHONPATH or ``sys.path``.
It is thus good practise for projects to either put ``conftest.py``
under a package scope or to never import anything from a
conftest.py file.
.. _`external plugins`:
.. _`extplugins`:
Installing External Plugins / Searching
------------------------------------------------------
Installing a plugin happens through any usual Python installation
tool, for example::
pip install pytest-NAME
pip uninstall pytest-NAME
If a plugin is installed, py.test automatically finds and integrates it,
there is no need to activate it. Here is a list of known plugins:
* `pytest-capturelog <http://pypi.python.org/pypi/pytest-capturelog>`_:
to capture and assert about messages from the logging module
* `pytest-xdist <http://pypi.python.org/pypi/pytest-xdist>`_:
to distribute tests to CPUs and remote hosts, looponfailing mode,
see also :ref:`xdist`
* `pytest-cov <http://pypi.python.org/pypi/pytest-cov>`_:
coverage reporting, compatible with distributed testing
* `pytest-pep8 <http://pypi.python.org/pypi/pytest-pep8>`_:
a ``--pep8`` option to enable PEP8 compliance checking.
* `oejskit <http://pypi.python.org/pypi/oejskit>`_:
a plugin to run javascript unittests in life browsers
(**version 0.8.9 not compatible with pytest-2.0**)
You may discover more plugins through a `pytest- pypi.python.org search`_.
.. _`available installable plugins`:
.. _`pytest- pypi.python.org search`: http://pypi.python.org/pypi?%3Aaction=search&term=pytest-&submit=search
Writing a plugin by looking at examples
------------------------------------------------------
.. _`Distribute`: http://pypi.python.org/pypi/distribute
.. _`setuptools`: http://pypi.python.org/pypi/setuptools
If you want to write a plugin, there are many real-life examples
you can copy from:
* a custom collection example plugin: :ref:`yaml plugin`
* around 20 `builtin plugins`_ which comprise py.test's own functionality
* around 10 `external plugins`_ providing additional features
All of these plugins implement the documented `well specified hooks`_
to extend and add functionality.
.. _`setuptools entry points`:
Making your plugin installable by others
-----------------------------------------------
If you want to make your plugin externally available, you
may define a so-called entry point for your distribution so
that ``py.test`` finds your plugin module. Entry points are
a feature that is provided by `setuptools`_ or `Distribute`_.
py.test looks up the ``pytest11`` entrypoint to discover its
plugins and you can thus make your plugin available by definig
it in your setuptools/distribute-based setup-invocation:
.. sourcecode:: python
# sample ./setup.py file
from setuptools import setup
setup(
name="myproject",
packages = ['myproject']
# the following makes a plugin available to py.test
entry_points = {
'pytest11': [
'name_of_plugin = myproject.pluginmodule',
]
},
)
If a package is installed this way, py.test will load
``myproject.pluginmodule`` as a plugin which can define
`well specified hooks`_.
Plugin discovery order at tool startup
--------------------------------------------
py.test loads plugin modules at tool startup in the following way:
* by loading all builtin plugins
* by loading all plugins registered through `setuptools entry points`_.
* by pre-scanning the command line for the ``-p name`` option
and loading the specified plugin before actual command line parsing.
* by loading all :file:`conftest.py` files as inferred by the command line
invocation (test files and all of its *parent* directories).
Note that ``conftest.py`` files from *sub* directories are by default
not loaded at tool startup.
* by recursively loading all plugins specified by the
``pytest_plugins`` variable in ``conftest.py`` files
Requiring/Loading plugins in a test module or conftest file
-------------------------------------------------------------
You can require plugins in a test module or a conftest file like this::
pytest_plugins = "name1", "name2",
When the test module or conftest plugin is loaded the specified plugins
will be loaded as well. You can also use dotted path like this::
pytest_plugins = "myapp.testsupport.myplugin"
which will import the specified module as a py.test plugin.
Accessing another plugin by name
--------------------------------------------
If a plugin wants to collaborate with code from
another plugin it can obtain a reference through
the plugin manager like this:
.. sourcecode:: python
plugin = config.pluginmanager.getplugin("name_of_plugin")
If you want to look at the names of existing plugins, use
the ``--traceconfig`` option.
.. _`findpluginname`:
Finding out which plugins are active
----------------------------------------------------------------------------
If you want to find out which plugins are active in your
environment you can type::
py.test --traceconfig
and will get an extended test header which shows activated plugins
and their names. It will also print local plugins aka
:ref:`conftest.py <conftest>` files when they are loaded.
.. _`cmdunregister`:
Deactivating / unregistering a plugin by name
----------------------------------------------------------------------------
You can prevent plugins from loading or unregister them::
py.test -p no:NAME
This means that any subsequent try to activate/load the named
plugin will it already existing. See :ref:`findpluginname` for
how to obtain the name of a plugin.
.. _`builtin plugins`:
py.test default plugin reference
====================================
You can find the source code for the following plugins
in the `pytest repository <http://bitbucket.org/hpk42/pytest/>`_.
.. autosummary::
_pytest.assertion
_pytest.capture
_pytest.config
_pytest.doctest
_pytest.genscript
_pytest.helpconfig
_pytest.junitxml
_pytest.mark
_pytest.monkeypatch
_pytest.nose
_pytest.pastebin
_pytest.pdb
_pytest.pytester
_pytest.python
_pytest.recwarn
_pytest.resultlog
_pytest.runner
_pytest.main
_pytest.skipping
_pytest.terminal
_pytest.tmpdir
_pytest.unittest
.. _`well specified hooks`:
py.test hook reference
====================================
Hook specification and validation
-----------------------------------------
py.test calls hook functions to implement initialization, running,
test execution and reporting. When py.test loads a plugin it validates
that each hook function conforms to its respective hook specification.
Each hook function name and its argument names need to match a hook
specification. However, a hook function may accept *fewer* parameters
by simply not specifying them. If you mistype argument names or the
hook name itself you get an error showing the available arguments.
Initialization, command line and configuration hooks
--------------------------------------------------------------------
.. currentmodule:: _pytest.hookspec
.. autofunction:: pytest_cmdline_preparse
.. autofunction:: pytest_cmdline_parse
.. autofunction:: pytest_namespace
.. autofunction:: pytest_addoption
.. autofunction:: pytest_cmdline_main
.. autofunction:: pytest_configure
.. autofunction:: pytest_unconfigure
Generic "runtest" hooks
------------------------------
All all runtest related hooks receive a :py:class:`pytest.Item` object.
.. autofunction:: pytest_runtest_protocol
.. autofunction:: pytest_runtest_setup
.. autofunction:: pytest_runtest_call
.. autofunction:: pytest_runtest_teardown
.. autofunction:: pytest_runtest_makereport
For deeper understanding you may look at the default implementation of
these hooks in :py:mod:`_pytest.runner` and maybe also
in :py:mod:`_pytest.pdb` which interacts with :py:mod:`_pytest.capture`
and its input/output capturing in order to immediately drop
into interactive debugging when a test failure occurs.
The :py:mod:`_pytest.terminal` reported specifically uses
the reporting hook to print information about a test run.
Collection hooks
------------------------------
py.test calls the following hooks for collecting files and directories:
.. autofunction:: pytest_ignore_collect
.. autofunction:: pytest_collect_directory
.. autofunction:: pytest_collect_file
For influencing the collection of objects in Python modules
you can use the following hook:
.. autofunction:: pytest_pycollect_makeitem
Reporting hooks
------------------------------
Session related reporting hooks:
.. autofunction: pytest_collectstart
.. autofunction: pytest_itemcollected
.. autofunction: pytest_collectreport
.. autofunction: pytest_deselected
And here is the central hook for reporting about
test execution:
.. autofunction: pytest_runtest_logreport
Reference of important objects involved in hooks
===========================================================
.. autoclass:: _pytest.config.Config
:members:
.. autoclass:: _pytest.config.Parser
:members:
.. autoclass:: _pytest.main.Node(name, parent)
:members:
..
.. autoclass:: _pytest.main.File(fspath, parent)
:members:
.. autoclass:: _pytest.main.Item(name, parent)
:members:
.. autoclass:: _pytest.python.Module(name, parent)
:members:
.. autoclass:: _pytest.python.Class(name, parent)
:members:
.. autoclass:: _pytest.python.Function(name, parent)
:members:
.. autoclass:: _pytest.runner.CallInfo
:members:
.. autoclass:: _pytest.runner.TestReport
:members:
|