various documentation related refinements
--HG-- branch : trunk
This commit is contained in:
parent
a82a6bb058
commit
251fb0ab1c
|
@ -9,9 +9,12 @@ py.test reference documentation
|
||||||
xunit_setup.txt
|
xunit_setup.txt
|
||||||
capture.txt
|
capture.txt
|
||||||
monkeypatch.txt
|
monkeypatch.txt
|
||||||
|
tmpdir.txt
|
||||||
skipping.txt
|
skipping.txt
|
||||||
mark.txt
|
mark.txt
|
||||||
doctest.txt
|
|
||||||
recwarn.txt
|
recwarn.txt
|
||||||
reporting.txt
|
reporting.txt
|
||||||
|
debugging.txt
|
||||||
|
doctest.txt
|
||||||
|
unittest.txt
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
.. _`captures`:
|
||||||
|
|
||||||
Capturing of stdout/stderr output
|
Capturing of stdout/stderr output
|
||||||
=========================================================
|
=========================================================
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@ There are two ways in which ``py.test`` can perform capturing:
|
||||||
output from code like ``sys.stderr.write(...)`` will be captured with
|
output from code like ``sys.stderr.write(...)`` will be captured with
|
||||||
this method.
|
this method.
|
||||||
|
|
||||||
|
.. _`disable capturing`:
|
||||||
|
|
||||||
You can influence output capturing mechanisms from the command line::
|
You can influence output capturing mechanisms from the command line::
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ Customizing and Extending py.test
|
||||||
basic test configuration
|
basic test configuration
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
available command line options
|
Command line options
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
You can see command line options by running::
|
You can see command line options by running::
|
||||||
|
@ -26,10 +26,6 @@ allow to:
|
||||||
|
|
||||||
* `set option defaults`_
|
* `set option defaults`_
|
||||||
|
|
||||||
* `implement hooks`_
|
|
||||||
|
|
||||||
* `specify funcargs`_
|
|
||||||
|
|
||||||
or set particular variables to influence the testing process:
|
or set particular variables to influence the testing process:
|
||||||
|
|
||||||
* ``pytest_plugins``: list of named plugins to load
|
* ``pytest_plugins``: list of named plugins to load
|
||||||
|
@ -68,25 +64,6 @@ To find out about the particular switches and type::
|
||||||
This will print information about all options in your
|
This will print information about all options in your
|
||||||
environment, including your local plugins.
|
environment, including your local plugins.
|
||||||
|
|
||||||
.. _`basetemp`:
|
|
||||||
|
|
||||||
Temporary directories
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
You can create directories by calling one of two methods
|
|
||||||
on the config object:
|
|
||||||
|
|
||||||
- ``config.mktemp(basename)``: create and return a new tempdir
|
|
||||||
|
|
||||||
- ``config.ensuretemp(basename)``: create or return a new tempdir
|
|
||||||
|
|
||||||
temporary directories are created as sub directories of a per-session
|
|
||||||
testdir and will keep around the directories of the last three test
|
|
||||||
runs. You can set the base temporary directory through the command line
|
|
||||||
`--basetemp`` option. When distributing tests on the same machine,
|
|
||||||
``py.test`` takes care to configure a basetemp directory for the sub
|
|
||||||
processes such that all temporary data lands below below a single
|
|
||||||
per-test run basetemp directory.
|
|
||||||
|
|
||||||
.. _`function arguments`: funcargs.html
|
.. _`function arguments`: funcargs.html
|
||||||
.. _`extensions`:
|
.. _`extensions`:
|
||||||
|
@ -226,7 +203,6 @@ If you want to look at the names of existing plugins, use
|
||||||
the ``--traceconfig`` option.
|
the ``--traceconfig`` option.
|
||||||
|
|
||||||
.. _`well specified hooks`:
|
.. _`well specified hooks`:
|
||||||
.. _`implement hooks`:
|
|
||||||
|
|
||||||
py.test hook reference
|
py.test hook reference
|
||||||
====================================
|
====================================
|
||||||
|
@ -361,17 +337,21 @@ name. Given a filesystem ``fspath`` it is constructed as follows:
|
||||||
|
|
||||||
* import the root package as ``root``
|
* import the root package as ``root``
|
||||||
|
|
||||||
Complete reference of objects involved in hooks
|
Reference of important objects involved in hooks
|
||||||
===========================================================
|
===========================================================
|
||||||
|
|
||||||
|
.. autoclass:: pytest._config.Config
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autoclass:: pytest.collect.Item
|
||||||
|
:inherited-members:
|
||||||
|
|
||||||
|
.. autoclass:: pytest.collect.Node
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: pytest.plugin.runner.CallInfo
|
.. autoclass:: pytest.plugin.runner.CallInfo
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: pytest.plugin.runner.TestReport
|
.. autoclass:: pytest.plugin.runner.TestReport
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: pytest.collect.Node
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: pytest.collect.Item
|
|
||||||
:inherited-members:
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
Tracebacks and debugging Python failures
|
||||||
|
=================================================================
|
||||||
|
|
||||||
|
Stopping after the first (or N) failures
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
To stop the testing process after the first (N) failures::
|
||||||
|
|
||||||
|
py.test -x # stop after first failure
|
||||||
|
py.test -maxfail=2 # stop after two failures
|
||||||
|
|
||||||
|
Modifying traceback printing
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
Examples for modifying traceback printing::
|
||||||
|
|
||||||
|
py.test --showlocals # show local variables in tracebacks
|
||||||
|
py.test -l # show local variables (shortcut)
|
||||||
|
|
||||||
|
py.test --tb=long # the default informative traceback formatting
|
||||||
|
py.test --tb=native # the Python standard library formatting
|
||||||
|
py.test --tb=short # a shorter traceback format
|
||||||
|
py.test --tb=line # only one line per failure
|
||||||
|
|
||||||
|
Dropping to PDB (Python Debugger) on failures
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
.. _PDB: http://docs.python.org/library/pdb.html
|
||||||
|
|
||||||
|
Python comes with a builtin Python debugger called PDB_. ``py.test``
|
||||||
|
allows to drop into the PDB prompt via a command line option::
|
||||||
|
|
||||||
|
py.test --pdb
|
||||||
|
|
||||||
|
This will invoke the Python debugger on every failure. Often you might
|
||||||
|
only want to do this for the first failing test to understand a certain
|
||||||
|
failure situation::
|
||||||
|
|
||||||
|
py.test -x --pdb # drop to PDB on first failure, then end test session
|
||||||
|
py.test --pdb --maxfail=3 # drop to PDB for the first three failures
|
||||||
|
|
||||||
|
|
||||||
|
Setting a breakpoint / aka ``set_trace()``
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
If you want to set a breakpoint and enter the ``pdb.set_trace()`` you
|
||||||
|
can use a helper::
|
||||||
|
|
||||||
|
def test_function():
|
||||||
|
...
|
||||||
|
py.test.set_trace() # invoke PDB debugger and tracing
|
||||||
|
|
||||||
|
.. versionadded: 2.0.0
|
||||||
|
|
||||||
|
In previous versions you could only enter PDB tracing if
|
||||||
|
you :ref:`disable capturing`.
|
||||||
|
|
||||||
|
|
|
@ -43,12 +43,12 @@ and another like this::
|
||||||
then you can just invoke ``py.test`` without command line options::
|
then you can just invoke ``py.test`` without command line options::
|
||||||
|
|
||||||
$ py.test
|
$ py.test
|
||||||
============================= test session starts ==============================
|
=========================== test session starts ============================
|
||||||
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
||||||
test path 1: /tmp/doc-exec-224
|
test path 1: /tmp/doc-exec-288
|
||||||
|
|
||||||
conftest.py .
|
conftest.py .
|
||||||
example.rst .
|
example.rst .
|
||||||
mymodule.py .
|
mymodule.py .
|
||||||
|
|
||||||
=========================== 3 passed in 0.01 seconds ===========================
|
========================= 3 passed in 0.01 seconds =========================
|
||||||
|
|
|
@ -5,7 +5,7 @@ def test_function():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class TestClass:
|
class TestClass:
|
||||||
def test_method():
|
def test_method(self):
|
||||||
pass
|
pass
|
||||||
def test_anothermethod():
|
def test_anothermethod(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -31,14 +31,14 @@ into a test module::
|
||||||
Running the test looks like this::
|
Running the test looks like this::
|
||||||
|
|
||||||
$ py.test test_simplefactory.py
|
$ py.test test_simplefactory.py
|
||||||
============================= test session starts ==============================
|
=========================== test session starts ============================
|
||||||
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
||||||
test path 1: test_simplefactory.py
|
test path 1: test_simplefactory.py
|
||||||
|
|
||||||
test_simplefactory.py F
|
test_simplefactory.py F
|
||||||
|
|
||||||
=================================== FAILURES ===================================
|
================================= FAILURES =================================
|
||||||
________________________________ test_function _________________________________
|
______________________________ test_function _______________________________
|
||||||
|
|
||||||
myfuncarg = 42
|
myfuncarg = 42
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ Running the test looks like this::
|
||||||
E assert 42 == 17
|
E assert 42 == 17
|
||||||
|
|
||||||
test_simplefactory.py:5: AssertionError
|
test_simplefactory.py:5: AssertionError
|
||||||
=========================== 1 failed in 0.02 seconds ===========================
|
========================= 1 failed in 0.02 seconds =========================
|
||||||
|
|
||||||
This means that the test function was called with a ``myfuncarg`` value
|
This means that the test function was called with a ``myfuncarg`` value
|
||||||
of ``42`` and the assert fails accordingly. Here is how py.test
|
of ``42`` and the assert fails accordingly. Here is how py.test
|
||||||
|
@ -129,7 +129,7 @@ Basic generated test example
|
||||||
|
|
||||||
Let's consider this test module::
|
Let's consider this test module::
|
||||||
|
|
||||||
# content of ./test_example.py
|
# content of test_example.py
|
||||||
def pytest_generate_tests(metafunc):
|
def pytest_generate_tests(metafunc):
|
||||||
if "numiter" in metafunc.funcargnames:
|
if "numiter" in metafunc.funcargnames:
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
|
@ -141,14 +141,14 @@ Let's consider this test module::
|
||||||
Running this::
|
Running this::
|
||||||
|
|
||||||
$ py.test test_example.py
|
$ py.test test_example.py
|
||||||
============================= test session starts ==============================
|
=========================== test session starts ============================
|
||||||
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
||||||
test path 1: test_example.py
|
test path 1: test_example.py
|
||||||
|
|
||||||
test_example.py .........F
|
test_example.py .........F
|
||||||
|
|
||||||
=================================== FAILURES ===================================
|
================================= FAILURES =================================
|
||||||
_________________________________ test_func[9] _________________________________
|
_______________________________ test_func[9] _______________________________
|
||||||
|
|
||||||
numiter = 9
|
numiter = 9
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ Running this::
|
||||||
E assert 9 < 9
|
E assert 9 < 9
|
||||||
|
|
||||||
test_example.py:7: AssertionError
|
test_example.py:7: AssertionError
|
||||||
====================== 1 failed, 9 passed in 0.04 seconds ======================
|
==================== 1 failed, 9 passed in 0.04 seconds ====================
|
||||||
|
|
||||||
Here is what happens in detail:
|
Here is what happens in detail:
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,11 @@ will be undone.
|
||||||
|
|
||||||
.. background check:
|
.. background check:
|
||||||
$ py.test
|
$ py.test
|
||||||
============================= test session starts ==============================
|
=========================== test session starts ============================
|
||||||
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
||||||
test path 1: /tmp/doc-exec-232
|
test path 1: /tmp/doc-exec-296
|
||||||
|
|
||||||
=============================== in 0.00 seconds ===============================
|
============================= in 0.00 seconds =============================
|
||||||
|
|
||||||
Method reference of the monkeypatch function argument
|
Method reference of the monkeypatch function argument
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
|
|
||||||
capture output of logging module.
|
|
||||||
=================================
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
You can install the `pytest-capturelog pypi`_ package
|
|
||||||
with pip::
|
|
||||||
|
|
||||||
pip install pytest-capturelog
|
|
||||||
|
|
||||||
or with easy install::
|
|
||||||
|
|
||||||
easy_install pytest-capturelog
|
|
||||||
|
|
||||||
.. _`pytest-capturelog pypi`: http://pypi.python.org/pypi/pytest-capturelog/
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
If the plugin is installed log messages are captured by default and for
|
|
||||||
each failed test will be shown in the same manner as captured stdout and
|
|
||||||
stderr.
|
|
||||||
|
|
||||||
Running without options::
|
|
||||||
|
|
||||||
py.test test_capturelog.py
|
|
||||||
|
|
||||||
Shows failed tests like so::
|
|
||||||
|
|
||||||
-------------------------- Captured log ---------------------------
|
|
||||||
test_capturelog.py 26 INFO text going to logger
|
|
||||||
------------------------- Captured stdout -------------------------
|
|
||||||
text going to stdout
|
|
||||||
------------------------- Captured stderr -------------------------
|
|
||||||
text going to stderr
|
|
||||||
==================== 2 failed in 0.02 seconds =====================
|
|
||||||
|
|
||||||
By default each captured log message shows the module, line number,
|
|
||||||
log level and message. Showing the exact module and line number is
|
|
||||||
useful for testing and debugging. If desired the log format and date
|
|
||||||
format can be specified to anything that the logging module supports.
|
|
||||||
|
|
||||||
Running pytest specifying formatting options::
|
|
||||||
|
|
||||||
py.test --log-format="%(asctime)s %(levelname)s %(message)s" --log-date-format="%Y-%m-%d %H:%M:%S" test_capturelog.py
|
|
||||||
|
|
||||||
Shows failed tests like so::
|
|
||||||
|
|
||||||
-------------------------- Captured log ---------------------------
|
|
||||||
2010-04-10 14:48:44 INFO text going to logger
|
|
||||||
------------------------- Captured stdout -------------------------
|
|
||||||
text going to stdout
|
|
||||||
------------------------- Captured stderr -------------------------
|
|
||||||
text going to stderr
|
|
||||||
==================== 2 failed in 0.02 seconds =====================
|
|
||||||
|
|
||||||
Further it is possible to disable capturing of logs completely with::
|
|
||||||
|
|
||||||
py.test --nocapturelog test_capturelog.py
|
|
||||||
|
|
||||||
Shows failed tests in the normal manner as no logs were captured::
|
|
||||||
|
|
||||||
------------------------- Captured stdout -------------------------
|
|
||||||
text going to stdout
|
|
||||||
------------------------- Captured stderr -------------------------
|
|
||||||
text going to stderr
|
|
||||||
==================== 2 failed in 0.02 seconds =====================
|
|
||||||
|
|
||||||
command line options
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
``--nocapturelog``
|
|
||||||
disable log capture
|
|
||||||
``--log-format=LOG_FORMAT``
|
|
||||||
log format as used by the logging module
|
|
||||||
``--log-date-format=LOG_DATE_FORMAT``
|
|
||||||
log date format as used by the logging module
|
|
||||||
|
|
||||||
.. include:: links.txt
|
|
|
@ -1,28 +0,0 @@
|
||||||
|
|
||||||
log invocations of extension hooks to a file.
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
command line options
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
``--hooklog=HOOKLOG``
|
|
||||||
write hook calls to the given file.
|
|
||||||
|
|
||||||
Start improving this plugin in 30 seconds
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
|
|
||||||
1. Download `pytest_hooklog.py`_ plugin source code
|
|
||||||
2. put it somewhere as ``pytest_hooklog.py`` into your import path
|
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
|
||||||
|
|
||||||
Checkout customize_, other plugins_ or `get in contact`_.
|
|
||||||
|
|
||||||
.. include:: links.txt
|
|
|
@ -1,207 +0,0 @@
|
||||||
|
|
||||||
hook specification sourcecode
|
|
||||||
=============================
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
"""
|
|
||||||
hook specifications for py.test plugins
|
|
||||||
"""
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Command line and configuration
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_namespace():
|
|
||||||
"return dict of name->object which will get stored at py.test. namespace"
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
|
||||||
"add optparse-style options via parser.addoption."
|
|
||||||
|
|
||||||
def pytest_addhooks(pluginmanager):
|
|
||||||
"add hooks via pluginmanager.registerhooks(module)"
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
|
||||||
""" called after command line options have been parsed.
|
|
||||||
and all plugins and initial conftest files been loaded.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def pytest_unconfigure(config):
|
|
||||||
""" called before test process is exited. """
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# collection hooks
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_ignore_collect(path, config):
|
|
||||||
""" return true value to prevent considering this path for collection.
|
|
||||||
This hook is consulted for all files and directories prior to considering
|
|
||||||
collection hooks.
|
|
||||||
"""
|
|
||||||
pytest_ignore_collect.firstresult = True
|
|
||||||
|
|
||||||
def pytest_collect_directory(path, parent):
|
|
||||||
""" return Collection node or None for the given path. """
|
|
||||||
pytest_collect_directory.firstresult = True
|
|
||||||
|
|
||||||
def pytest_collect_file(path, parent):
|
|
||||||
""" return Collection node or None for the given path. """
|
|
||||||
|
|
||||||
def pytest_collectstart(collector):
|
|
||||||
""" collector starts collecting. """
|
|
||||||
|
|
||||||
def pytest_collectreport(report):
|
|
||||||
""" collector finished collecting. """
|
|
||||||
|
|
||||||
def pytest_deselected(items):
|
|
||||||
""" called for test items deselected by keyword. """
|
|
||||||
|
|
||||||
def pytest_make_collect_report(collector):
|
|
||||||
""" perform a collection and return a collection. """
|
|
||||||
pytest_make_collect_report.firstresult = True
|
|
||||||
|
|
||||||
# XXX rename to item_collected()? meaning in distribution context?
|
|
||||||
def pytest_itemstart(item, node=None):
|
|
||||||
""" test item gets collected. """
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Python test function related hooks
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_pycollect_makemodule(path, parent):
|
|
||||||
""" return a Module collector or None for the given path.
|
|
||||||
This hook will be called for each matching test module path.
|
|
||||||
The pytest_collect_file hook needs to be used if you want to
|
|
||||||
create test modules for files that do not match as a test module.
|
|
||||||
"""
|
|
||||||
pytest_pycollect_makemodule.firstresult = True
|
|
||||||
|
|
||||||
def pytest_pycollect_makeitem(collector, name, obj):
|
|
||||||
""" return custom item/collector for a python object in a module, or None. """
|
|
||||||
pytest_pycollect_makeitem.firstresult = True
|
|
||||||
|
|
||||||
def pytest_pyfunc_call(pyfuncitem):
|
|
||||||
""" call underlying test function. """
|
|
||||||
pytest_pyfunc_call.firstresult = True
|
|
||||||
|
|
||||||
def pytest_generate_tests(metafunc):
|
|
||||||
""" generate (multiple) parametrized calls to a test function."""
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# generic runtest related hooks
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_runtest_protocol(item):
|
|
||||||
""" implement fixture, run and report about the given test item. """
|
|
||||||
pytest_runtest_protocol.firstresult = True
|
|
||||||
|
|
||||||
def pytest_runtest_setup(item):
|
|
||||||
""" called before pytest_runtest_call(). """
|
|
||||||
|
|
||||||
def pytest_runtest_call(item):
|
|
||||||
""" execute test item. """
|
|
||||||
|
|
||||||
def pytest_runtest_teardown(item):
|
|
||||||
""" called after pytest_runtest_call(). """
|
|
||||||
|
|
||||||
def pytest_runtest_makereport(item, call):
|
|
||||||
""" make a test report for the given item and call outcome. """
|
|
||||||
pytest_runtest_makereport.firstresult = True
|
|
||||||
|
|
||||||
def pytest_runtest_logreport(report):
|
|
||||||
""" process item test report. """
|
|
||||||
|
|
||||||
# special handling for final teardown - somewhat internal for now
|
|
||||||
def pytest__teardown_final(session):
|
|
||||||
""" called before test session finishes. """
|
|
||||||
pytest__teardown_final.firstresult = True
|
|
||||||
|
|
||||||
def pytest__teardown_final_logerror(report):
|
|
||||||
""" called if runtest_teardown_final failed. """
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# test session related hooks
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_sessionstart(session):
|
|
||||||
""" before session.main() is called. """
|
|
||||||
|
|
||||||
def pytest_sessionfinish(session, exitstatus):
|
|
||||||
""" whole test run finishes. """
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# hooks for influencing reporting (invoked from pytest_terminal)
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_report_header(config):
|
|
||||||
""" return a string to be displayed as header info for terminal reporting."""
|
|
||||||
|
|
||||||
def pytest_report_teststatus(report):
|
|
||||||
""" return result-category, shortletter and verbose word for reporting."""
|
|
||||||
pytest_report_teststatus.firstresult = True
|
|
||||||
|
|
||||||
def pytest_terminal_summary(terminalreporter):
|
|
||||||
""" add additional section in terminal summary reporting. """
|
|
||||||
|
|
||||||
def pytest_report_iteminfo(item):
|
|
||||||
""" return (fspath, lineno, name) for the item.
|
|
||||||
the information is used for result display and to sort tests
|
|
||||||
"""
|
|
||||||
pytest_report_iteminfo.firstresult = True
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# doctest hooks
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_doctest_prepare_content(content):
|
|
||||||
""" return processed content for a given doctest"""
|
|
||||||
pytest_doctest_prepare_content.firstresult = True
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# error handling and internal debugging hooks
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def pytest_plugin_registered(plugin, manager):
|
|
||||||
""" a new py lib plugin got registered. """
|
|
||||||
|
|
||||||
def pytest_plugin_unregistered(plugin):
|
|
||||||
""" a py lib plugin got unregistered. """
|
|
||||||
|
|
||||||
def pytest_internalerror(excrepr):
|
|
||||||
""" called for internal errors. """
|
|
||||||
|
|
||||||
def pytest_keyboard_interrupt(excinfo):
|
|
||||||
""" called for keyboard interrupt. """
|
|
||||||
|
|
||||||
def pytest_trace(category, msg):
|
|
||||||
""" called for debug info. """
|
|
||||||
|
|
||||||
hook specification sourcecode
|
|
||||||
=============================
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_gwmanage_newgateway(gateway, platinfo):
|
|
||||||
""" called on new raw gateway creation. """
|
|
||||||
|
|
||||||
def pytest_gwmanage_rsyncstart(source, gateways):
|
|
||||||
""" called before rsyncing a directory to remote gateways takes place. """
|
|
||||||
|
|
||||||
def pytest_gwmanage_rsyncfinish(source, gateways):
|
|
||||||
""" called after rsyncing a directory to remote gateways takes place. """
|
|
||||||
|
|
||||||
def pytest_configure_node(node):
|
|
||||||
""" configure node information before it gets instantiated. """
|
|
||||||
|
|
||||||
def pytest_testnodeready(node):
|
|
||||||
""" Test Node is ready to operate. """
|
|
||||||
|
|
||||||
def pytest_testnodedown(node, error):
|
|
||||||
""" Test Node is down. """
|
|
||||||
|
|
||||||
def pytest_rescheduleitems(items):
|
|
||||||
""" reschedule Items from a node that went down. """
|
|
||||||
|
|
||||||
.. include:: links.txt
|
|
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
logging of test results in JUnit-XML format, for use with Hudson
|
|
||||||
================================================================
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
and build integration servers. Based on initial code from Ross Lawley.
|
|
||||||
|
|
||||||
command line options
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
``--junitxml=path``
|
|
||||||
create junit-xml style report file at given path.
|
|
||||||
``--junitprefix=str``
|
|
||||||
prepend prefix to classnames in junit-xml output
|
|
||||||
|
|
||||||
Start improving this plugin in 30 seconds
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
|
|
||||||
1. Download `pytest_junitxml.py`_ plugin source code
|
|
||||||
2. put it somewhere as ``pytest_junitxml.py`` into your import path
|
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
|
||||||
|
|
||||||
Checkout customize_, other plugins_ or `get in contact`_.
|
|
||||||
|
|
||||||
.. include:: links.txt
|
|
|
@ -1,28 +0,0 @@
|
||||||
|
|
||||||
interactive debugging with the Python Debugger.
|
|
||||||
===============================================
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
command line options
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
``--pdb``
|
|
||||||
start the interactive Python debugger on errors.
|
|
||||||
|
|
||||||
Start improving this plugin in 30 seconds
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
|
|
||||||
1. Download `pytest_pdb.py`_ plugin source code
|
|
||||||
2. put it somewhere as ``pytest_pdb.py`` into your import path
|
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
|
||||||
|
|
||||||
Checkout customize_, other plugins_ or `get in contact`_.
|
|
||||||
|
|
||||||
.. include:: links.txt
|
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
provide temporary directories to test functions.
|
|
||||||
================================================
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
usage example::
|
|
||||||
|
|
||||||
def test_plugin(tmpdir):
|
|
||||||
tmpdir.join("hello").write("hello")
|
|
||||||
|
|
||||||
.. _`py.path.local`: ../../path.html
|
|
||||||
|
|
||||||
.. _`tmpdir funcarg`:
|
|
||||||
|
|
||||||
|
|
||||||
the 'tmpdir' test function argument
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
return a temporary directory path object
|
|
||||||
unique to each test function invocation,
|
|
||||||
created as a sub directory of the base temporary
|
|
||||||
directory. The returned object is a `py.path.local`_
|
|
||||||
path object.
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
|
|
||||||
automatically discover and run traditional "unittest.py" style tests.
|
|
||||||
=====================================================================
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
Usage
|
|
||||||
----------------
|
|
||||||
|
|
||||||
This plugin collects and runs Python `unittest.py style`_ tests.
|
|
||||||
It will automatically collect ``unittest.TestCase`` subclasses
|
|
||||||
and their ``test`` methods from the test modules of a project
|
|
||||||
(usually following the ``test_*.py`` pattern).
|
|
||||||
|
|
||||||
This plugin is enabled by default.
|
|
||||||
|
|
||||||
.. _`unittest.py style`: http://docs.python.org/library/unittest.html
|
|
||||||
|
|
||||||
Start improving this plugin in 30 seconds
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
|
|
||||||
1. Download `pytest_unittest.py`_ plugin source code
|
|
||||||
2. put it somewhere as ``pytest_unittest.py`` into your import path
|
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
|
||||||
|
|
||||||
Checkout customize_, other plugins_ or `get in contact`_.
|
|
||||||
|
|
||||||
.. include:: links.txt
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
working with temporary directories and files
|
||||||
|
================================================
|
||||||
|
|
||||||
|
the 'tmpdir' test function argument
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
You can use the ``tmpdir`` function argument which will
|
||||||
|
provide a temporary directory unique to the test invocation,
|
||||||
|
created in the `base temporary directory`_.
|
||||||
|
|
||||||
|
``tmpdir`` is a `py.path.local`_ object which offers ``os.path`` methods
|
||||||
|
and more. Here is an example test usage::
|
||||||
|
|
||||||
|
# content of test_tmpdir.py
|
||||||
|
import os
|
||||||
|
def test_create_file(tmpdir):
|
||||||
|
p = tmpdir.mkdir("sub").join("hello.txt")
|
||||||
|
p.write("content")
|
||||||
|
assert p.read() == "content"
|
||||||
|
assert len(os.listdir(str(tmpdir))) == 1
|
||||||
|
assert 0
|
||||||
|
|
||||||
|
Running this would result in a passed test except for the last
|
||||||
|
``assert 0`` line which we use to look at values::
|
||||||
|
|
||||||
|
$ py.test test_tmpdir.py
|
||||||
|
=========================== test session starts ============================
|
||||||
|
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
||||||
|
test path 1: test_tmpdir.py
|
||||||
|
|
||||||
|
test_tmpdir.py F
|
||||||
|
|
||||||
|
================================= FAILURES =================================
|
||||||
|
_____________________________ test_create_file _____________________________
|
||||||
|
|
||||||
|
tmpdir = local('/tmp/pytest-427/test_create_file0')
|
||||||
|
|
||||||
|
def test_create_file(tmpdir):
|
||||||
|
p = tmpdir.mkdir("sub").join("hello.txt")
|
||||||
|
p.write("content")
|
||||||
|
assert p.read() == "content"
|
||||||
|
assert len(os.listdir(str(tmpdir))) == 1
|
||||||
|
> assert 0
|
||||||
|
E assert 0
|
||||||
|
|
||||||
|
test_tmpdir.py:7: AssertionError
|
||||||
|
========================= 1 failed in 0.03 seconds =========================
|
||||||
|
|
||||||
|
.. _`base temporary directory`:
|
||||||
|
|
||||||
|
the default base temporary directory
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
..
|
||||||
|
You can create directories by calling one of two methods
|
||||||
|
on the config object:
|
||||||
|
- ``config.mktemp(basename)``: create and return a new tempdir
|
||||||
|
- ``config.ensuretemp(basename)``: create or return a new tempdir
|
||||||
|
|
||||||
|
Temporary directories are by default created as sub directories of
|
||||||
|
the system temporary directory. The name will be ``pytest-NUM`` where
|
||||||
|
``NUM`` will be incremenated with each test run. Moreover, entries older
|
||||||
|
than 3 temporary directories will be removed.
|
||||||
|
|
||||||
|
You can override the default temporary directory logic and set it like this::
|
||||||
|
|
||||||
|
py.test --basetemp=mydir
|
||||||
|
|
||||||
|
When distributing tests on the local machine, ``py.test`` takes care to
|
||||||
|
configure a basetemp directory for the sub processes such that all
|
||||||
|
temporary data lands below below a single per-test run basetemp directory.
|
||||||
|
|
||||||
|
.. _`py.path.local`: http://pylib.org/path.html
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
automatically discover and run traditional "unittest.py" style tests.
|
||||||
|
=====================================================================
|
||||||
|
|
||||||
|
py.test has limited support for running Python `unittest.py style`_ tests.
|
||||||
|
It will automatically collect ``unittest.TestCase`` subclasses
|
||||||
|
and their ``test`` methods in test files. It will invoke
|
||||||
|
``setUp/tearDown`` methods but also perform py.test's standard ways
|
||||||
|
of treating tests like IO capturing::
|
||||||
|
|
||||||
|
# content of test_unittest.py
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
class MyTest(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
print ("hello") # output is captured
|
||||||
|
def test_method(self):
|
||||||
|
x = 1
|
||||||
|
self.assertEquals(x, 3)
|
||||||
|
|
||||||
|
Running it yields::
|
||||||
|
|
||||||
|
$ py.test test_unittest.py
|
||||||
|
=========================== test session starts ============================
|
||||||
|
platform linux2 -- Python 2.6.5 -- pytest-2.0.0dev0
|
||||||
|
test path 1: test_unittest.py
|
||||||
|
|
||||||
|
test_unittest.py F
|
||||||
|
|
||||||
|
================================= FAILURES =================================
|
||||||
|
____________________________ MyTest.test_method ____________________________
|
||||||
|
|
||||||
|
self = <test_unittest.MyTest testMethod=run>
|
||||||
|
|
||||||
|
def test_method(self):
|
||||||
|
x = 1
|
||||||
|
> self.assertEquals(x, 3)
|
||||||
|
|
||||||
|
test_unittest.py:8:
|
||||||
|
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||||
|
|
||||||
|
self = <test_unittest.MyTest testMethod=run>, first = 1, second = 3
|
||||||
|
msg = None
|
||||||
|
|
||||||
|
def failUnlessEqual(self, first, second, msg=None):
|
||||||
|
"""Fail if the two objects are unequal as determined by the '=='
|
||||||
|
operator.
|
||||||
|
"""
|
||||||
|
if not first == second:
|
||||||
|
raise self.failureException, \
|
||||||
|
> (msg or '%r != %r' % (first, second))
|
||||||
|
E AssertionError: 1 != 3
|
||||||
|
|
||||||
|
/usr/lib/python2.6/unittest.py:350: AssertionError
|
||||||
|
----------------------------- Captured stdout ------------------------------
|
||||||
|
hello
|
||||||
|
========================= 1 failed in 0.02 seconds =========================
|
||||||
|
|
||||||
|
This plugin is enabled by default.
|
||||||
|
|
||||||
|
.. _`unittest.py style`: http://docs.python.org/library/unittest.html
|
||||||
|
|
|
@ -226,18 +226,19 @@ class Error(Exception):
|
||||||
""" Test Configuration Error. """
|
""" Test Configuration Error. """
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
""" access to config values, pluginmanager and plugin hooks. """
|
""" access to configuration values, pluginmanager and plugin hooks. """
|
||||||
Option = py.std.optparse.Option
|
Option = py.std.optparse.Option
|
||||||
Error = Error
|
Error = Error
|
||||||
basetemp = None
|
basetemp = None
|
||||||
_sessionclass = None
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
#: command line option values
|
||||||
self.option = CmdOptions()
|
self.option = CmdOptions()
|
||||||
self._parser = Parser(
|
self._parser = Parser(
|
||||||
usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
|
usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
|
||||||
processopt=self._processopt,
|
processopt=self._processopt,
|
||||||
)
|
)
|
||||||
|
#: a pluginmanager instance
|
||||||
self.pluginmanager = PluginManager()
|
self.pluginmanager = PluginManager()
|
||||||
self._conftest = Conftest(onimport=self._onimportconftest)
|
self._conftest = Conftest(onimport=self._onimportconftest)
|
||||||
self.hook = self.pluginmanager.hook
|
self.hook = self.pluginmanager.hook
|
||||||
|
@ -287,9 +288,8 @@ class Config(object):
|
||||||
self.pluginmanager.do_addoption(self._parser)
|
self.pluginmanager.do_addoption(self._parser)
|
||||||
|
|
||||||
def parse(self, args):
|
def parse(self, args):
|
||||||
""" parse cmdline arguments into this config object.
|
# cmdline arguments into this config object.
|
||||||
Note that this can only be called once per testing process.
|
# Note that this can only be called once per testing process.
|
||||||
"""
|
|
||||||
assert not hasattr(self, 'args'), (
|
assert not hasattr(self, 'args'), (
|
||||||
"can only parse cmdline args at most once per Config object")
|
"can only parse cmdline args at most once per Config object")
|
||||||
self._preparse(args)
|
self._preparse(args)
|
||||||
|
@ -352,10 +352,10 @@ class Config(object):
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def addoptions(self, groupname, *specs):
|
def addoptions(self, groupname, *specs):
|
||||||
""" add a named group of options to the current testing session.
|
# add a named group of options to the current testing session.
|
||||||
This function gets invoked during testing session initialization.
|
# This function gets invoked during testing session initialization.
|
||||||
"""
|
py.log._apiwarn("1.0",
|
||||||
py.log._apiwarn("1.0", "define pytest_addoptions(parser) to add options", stacklevel=2)
|
"define pytest_addoptions(parser) to add options", stacklevel=2)
|
||||||
group = self._parser.getgroup(groupname)
|
group = self._parser.getgroup(groupname)
|
||||||
for opt in specs:
|
for opt in specs:
|
||||||
group._addoption_instance(opt)
|
group._addoption_instance(opt)
|
||||||
|
@ -365,7 +365,7 @@ class Config(object):
|
||||||
return self._parser.addoption(*optnames, **attrs)
|
return self._parser.addoption(*optnames, **attrs)
|
||||||
|
|
||||||
def getvalueorskip(self, name, path=None):
|
def getvalueorskip(self, name, path=None):
|
||||||
""" return getvalue() or call py.test.skip if no value exists. """
|
""" return getvalue(name) or call py.test.skip if no value exists. """
|
||||||
try:
|
try:
|
||||||
val = self.getvalue(name, path)
|
val = self.getvalue(name, path)
|
||||||
if val is None:
|
if val is None:
|
||||||
|
|
|
@ -34,7 +34,9 @@ class Node(object):
|
||||||
#: the parent collector node.
|
#: the parent collector node.
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
|
#: the test config object
|
||||||
self.config = config or parent.config
|
self.config = config or parent.config
|
||||||
|
|
||||||
#: the collection this node is part of.
|
#: the collection this node is part of.
|
||||||
self.collection = collection or getattr(parent, 'collection', None)
|
self.collection = collection or getattr(parent, 'collection', None)
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
"""
|
"""
|
||||||
automatically discover and run traditional "unittest.py" style tests.
|
automatically discover and run traditional "unittest.py" style tests.
|
||||||
|
|
||||||
Usage
|
|
||||||
----------------
|
|
||||||
|
|
||||||
This plugin collects and runs Python `unittest.py style`_ tests.
|
|
||||||
It will automatically collect ``unittest.TestCase`` subclasses
|
|
||||||
and their ``test`` methods from the test modules of a project
|
|
||||||
(usually following the ``test_*.py`` pattern).
|
|
||||||
|
|
||||||
This plugin is enabled by default.
|
|
||||||
|
|
||||||
.. _`unittest.py style`: http://docs.python.org/library/unittest.html
|
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
import sys
|
import sys
|
||||||
|
|
21
tox.ini
21
tox.ini
|
@ -24,29 +24,28 @@ commands=
|
||||||
py.test -n3 -rfsxX \
|
py.test -n3 -rfsxX \
|
||||||
--junitxml={envlogdir}/junit-{envname}.xml []
|
--junitxml={envlogdir}/junit-{envname}.xml []
|
||||||
|
|
||||||
|
[testenv:allplugins]
|
||||||
|
deps=
|
||||||
|
pytest-xdist-*
|
||||||
|
pytest-xdist-*
|
||||||
|
|
||||||
[testenv:py26]
|
[testenv:py26]
|
||||||
basepython=python2.6
|
basepython=python2.6
|
||||||
[testenv:doc]
|
[testenv:doc]
|
||||||
basepython=python
|
basepython=python
|
||||||
changedir={toxinidir}
|
changedir=doc
|
||||||
deps=docutils
|
deps=sphinx
|
||||||
pygments
|
{distshare}/pylib-*
|
||||||
{distshare}/py-*
|
|
||||||
{distshare}/pytest-xdist-*
|
{distshare}/pytest-xdist-*
|
||||||
pytest-figleaf
|
|
||||||
pytest-coverage
|
|
||||||
pytest-cov
|
|
||||||
pytest-capturelog
|
|
||||||
|
|
||||||
commands=
|
commands=
|
||||||
{envpython} bin-for-dist/makepluginlist.py
|
make html
|
||||||
py.test [doc] -rsfxX --junitxml={envlogdir}/junit-{envname}s.xml --forcegen
|
|
||||||
|
|
||||||
[testenv:py31]
|
[testenv:py31]
|
||||||
deps= {distshare}/pylib-*
|
deps= {distshare}/pylib-*
|
||||||
|
|
||||||
[testenv:py32]
|
[testenv:py32]
|
||||||
deps=
|
deps= {distshare}/pylib-*
|
||||||
|
|
||||||
#{distshare}/pytest-xdist-*
|
#{distshare}/pytest-xdist-*
|
||||||
#[testenv:pypy]
|
#[testenv:pypy]
|
||||||
|
|
Loading…
Reference in New Issue