Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4d213f83d | ||
|
|
289ee1c6ea | ||
|
|
f41f7fda68 | ||
|
|
9ed127b5da | ||
|
|
525b08bc5c | ||
|
|
fae34ca5e3 | ||
|
|
0852e84d9f | ||
|
|
76db624639 | ||
|
|
1e6ec9941c |
1
.hgtags
1
.hgtags
@@ -49,3 +49,4 @@ e5e1746a197f0398356a43fbe2eebac9690f795d 2.1.0
|
||||
92b916483c1e65a80dc80e3f7816b39e84b36a4d 2.2.2
|
||||
3c11c5c9776f3c678719161e96cc0a08169c1cb8 2.2.3
|
||||
ad9fe504a371ad8eb613052d58f229aa66f53527 2.2.4
|
||||
c27a60097767c16a54ae56d9669a77925b213b9b 2.3.0
|
||||
|
||||
18
CHANGELOG
18
CHANGELOG
@@ -1,10 +1,22 @@
|
||||
Changes between 2.3.0 and 2.3.1
|
||||
-----------------------------------
|
||||
|
||||
- fix issue202 - fix regression: using "self" from fixture functions now
|
||||
works as expected (it's the same "self" instance that a test method
|
||||
which uses the fixture sees)
|
||||
|
||||
- skip pexpect using tests (test_pdb.py mostly) on freebsd* systems
|
||||
due to pexpect not supporting it properly (hanging)
|
||||
|
||||
- link to web pages from --markers output which provides help for
|
||||
pytest.mark.* usage.
|
||||
|
||||
Changes between 2.2.4 and 2.3.0
|
||||
-----------------------------------
|
||||
|
||||
- fix issue202 - better automatic names for parametrized test functions
|
||||
- fix issue139 - introduce @pytest.fixture which allows direct scoping
|
||||
and parametrization of funcarg factories. Introduce new @pytest.setup
|
||||
marker to allow the writing of setup functions which accept funcargs.
|
||||
and parametrization of funcarg factories.
|
||||
- fix issue198 - conftest fixtures were not found on windows32 in some
|
||||
circumstances with nested directory structures due to path manipulation issues
|
||||
- fix issue193 skip test functions with were parametrized with empty
|
||||
@@ -14,7 +26,7 @@ Changes between 2.2.4 and 2.3.0
|
||||
- introduce re-ordering of tests by resource and parametrization setup
|
||||
which takes precedence to the usual file-ordering
|
||||
- fix issue185 monkeypatching time.time does not cause pytest to fail
|
||||
- fix issue172 duplicate call of pytest.setup-decoratored setup_module
|
||||
- fix issue172 duplicate call of pytest.fixture decoratored setup_module
|
||||
functions
|
||||
- fix junitxml=path construction so that if tests change the
|
||||
current working directory and the path is a relative path
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#
|
||||
__version__ = '2.3.0'
|
||||
__version__ = '2.3.1'
|
||||
|
||||
@@ -532,6 +532,8 @@ class TmpTestdir:
|
||||
pytest.skip("pypy-64 bit not supported")
|
||||
if sys.platform == "darwin":
|
||||
pytest.xfail("pexpect does not work reliably on darwin?!")
|
||||
if sys.platform.startswith("freebsd"):
|
||||
pytest.xfail("pexpect does not work reliably on freebsd")
|
||||
logfile = self.tmpdir.join("spawn.out")
|
||||
child = pexpect.spawn(cmd, logfile=logfile.open("w"))
|
||||
child.timeout = expect_timeout
|
||||
|
||||
@@ -12,6 +12,16 @@ cutdir = py.path.local(_pytest.__file__).dirpath()
|
||||
|
||||
callable = py.builtin.callable
|
||||
|
||||
def getimfunc(func):
|
||||
try:
|
||||
return func.__func__
|
||||
except AttributeError:
|
||||
try:
|
||||
return func.im_func
|
||||
except AttributeError:
|
||||
return func
|
||||
|
||||
|
||||
class FixtureFunctionMarker:
|
||||
def __init__(self, scope, params, autouse=False):
|
||||
self.scope = scope
|
||||
@@ -100,10 +110,12 @@ def pytest_configure(config):
|
||||
"times passing in multiple different argument value sets. Example: "
|
||||
"@parametrize('arg1', [1,2]) would lead to two calls of the decorated "
|
||||
"test function, one with arg1=1 and another with arg1=2."
|
||||
" see http://pytest.org/latest/parametrize.html for more info and "
|
||||
"examples."
|
||||
)
|
||||
config.addinivalue_line("markers",
|
||||
"usefixtures(fixturename1, fixturename2, ...): mark tests as needing "
|
||||
"all of the specified fixtures."
|
||||
"all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures "
|
||||
)
|
||||
|
||||
def pytest_sessionstart(session):
|
||||
@@ -1621,7 +1633,19 @@ class FixtureDef:
|
||||
if self.unittest:
|
||||
result = self.func(request.instance, **kwargs)
|
||||
else:
|
||||
result = self.func(**kwargs)
|
||||
fixturefunc = self.func
|
||||
# the fixture function needs to be bound to the actual
|
||||
# request.instance so that code working with "self" behaves
|
||||
# as expected. XXX request.instance should maybe return None
|
||||
# instead of raising AttributeError
|
||||
try:
|
||||
if request.instance is not None:
|
||||
fixturefunc = getimfunc(self.func)
|
||||
if fixturefunc != self.func:
|
||||
fixturefunc = fixturefunc.__get__(request.instance)
|
||||
except AttributeError:
|
||||
pass
|
||||
result = fixturefunc(**kwargs)
|
||||
self.active = True
|
||||
self.cached_result = result
|
||||
return result
|
||||
|
||||
@@ -11,17 +11,18 @@ def pytest_addoption(parser):
|
||||
|
||||
def pytest_configure(config):
|
||||
config.addinivalue_line("markers",
|
||||
"skipif(*conditions): skip the given test function if evaluation "
|
||||
"of all conditions has a True value. Evaluation happens within the "
|
||||
"skipif(condition): skip the given test function if eval(condition) "
|
||||
"results in a True value. Evaluation happens within the "
|
||||
"module global context. Example: skipif('sys.platform == \"win32\"') "
|
||||
"skips the test if we are on the win32 platform. "
|
||||
"skips the test if we are on the win32 platform. see "
|
||||
"http://pytest.org/latest/skipping.html"
|
||||
)
|
||||
config.addinivalue_line("markers",
|
||||
"xfail(*conditions, reason=None, run=True): mark the the test function "
|
||||
"as an expected failure. Optionally specify a reason and run=False "
|
||||
"if you don't even want to execute the test function. Any positional "
|
||||
"condition strings will be evaluated (like with skipif) and if one is "
|
||||
"False the marker will not be applied."
|
||||
"xfail(condition, reason=None, run=True): mark the the test function "
|
||||
"as an expected failure if eval(condition) has a True value. "
|
||||
"Optionally specify a reason for better reporting and run=False if "
|
||||
"you don't even want to execute the test function. See "
|
||||
"http://pytest.org/latest/skipping.html"
|
||||
)
|
||||
|
||||
def pytest_namespace():
|
||||
|
||||
@@ -12,6 +12,8 @@ PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
SITETARGET=latest
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
|
||||
|
||||
regen:
|
||||
@@ -40,10 +42,10 @@ clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
install: html
|
||||
rsync -avz _build/html/ pytest.org:/www/pytest.org/latest
|
||||
rsync -avz _build/html/ pytest.org:/www/pytest.org/$(SITETARGET)
|
||||
|
||||
installpdf: latexpdf
|
||||
@scp $(BUILDDIR)/latex/pytest.pdf pytest.org:/www/pytest.org/latest
|
||||
@scp $(BUILDDIR)/latex/pytest.pdf pytest.org:/www/pytest.org/$(SITETARGET)
|
||||
|
||||
installall: clean install installpdf
|
||||
@echo "done"
|
||||
|
||||
39
doc/en/announce/release-2.3.1.txt
Normal file
39
doc/en/announce/release-2.3.1.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
pytest-2.3.1: fix regression with factory functions
|
||||
===========================================================================
|
||||
|
||||
pytest-2.3.1 is a quick follow-up release:
|
||||
|
||||
- fix issue202 - regression with fixture functions/funcarg factories:
|
||||
using "self" is now safe again and works as in 2.2.4. Thanks
|
||||
to Eduard Schettino for the quick bug report.
|
||||
|
||||
- disable pexpect pytest self tests on Freebsd - thanks Koob for the
|
||||
quick reporting
|
||||
|
||||
- fix/improve interactive docs with --markers
|
||||
|
||||
See
|
||||
|
||||
http://pytest.org/
|
||||
|
||||
for general information. To install or upgrade pytest:
|
||||
|
||||
pip install -U pytest # or
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel
|
||||
|
||||
|
||||
Changes between 2.3.0 and 2.3.1
|
||||
-----------------------------------
|
||||
|
||||
- fix issue202 - fix regression: using "self" from fixture functions now
|
||||
works as expected (it's the same "self" instance that a test method
|
||||
which uses the fixture sees)
|
||||
|
||||
- skip pexpect using tests (test_pdb.py mostly) on freebsd* systems
|
||||
due to pexpect not supporting it properly (hanging)
|
||||
|
||||
- link to web pages from --markers output which provides help for
|
||||
pytest.mark.* usage.
|
||||
@@ -26,7 +26,7 @@ you will see the return value of the function call::
|
||||
|
||||
$ py.test test_assert1.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_assert1.py F
|
||||
@@ -110,7 +110,7 @@ if you run this module::
|
||||
|
||||
$ py.test test_assert2.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_assert2.py F
|
||||
|
||||
@@ -64,7 +64,7 @@ of the failing function and hide the other one::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
|
||||
test_module.py .F
|
||||
@@ -78,7 +78,7 @@ of the failing function and hide the other one::
|
||||
|
||||
test_module.py:9: AssertionError
|
||||
----------------------------- Captured stdout ------------------------------
|
||||
setting up <function test_func2 at 0x2d98050>
|
||||
setting up <function test_func2 at 0x240e050>
|
||||
==================== 1 failed, 1 passed in 0.01 seconds ====================
|
||||
|
||||
Accessing captured output from a test function
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
# The short X.Y version.
|
||||
version = release = "2.3.0"
|
||||
version = release = "2.3.1"
|
||||
|
||||
import sys, os
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ then you can just invoke ``py.test`` without command line options::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
mymodule.py .
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
|
||||
.. highlightlang:: python
|
||||
|
||||
.. _myapp:
|
||||
|
||||
Building an SSH connecting Application fixture
|
||||
==========================================================
|
||||
|
||||
The goal of this tutorial-example is to show how you can put efficient
|
||||
test support and fixture code in one place, allowing test modules and
|
||||
test functions to stay ignorant of importing, configuration or
|
||||
setup/teardown details.
|
||||
|
||||
The tutorial implements a simple ``RemoteInterpreter`` object that
|
||||
allows evaluation of python expressions. We are going to use
|
||||
the `execnet <http://codespeak.net/execnet>`_ package for the
|
||||
underlying cross-python bridge functionality.
|
||||
|
||||
|
||||
Step 1: Implementing a first test
|
||||
--------------------------------------------------------------
|
||||
|
||||
Let's write a simple test function using a not yet defined ``interp`` fixture::
|
||||
|
||||
# content of test_remoteinterpreter.py
|
||||
|
||||
def test_eval_simple(interp):
|
||||
assert interp.eval("6*9") == 42
|
||||
|
||||
The test function needs an argument named `interp` and therefore pytest will
|
||||
look for a :ref:`fixture function` that matches this name. We'll define it
|
||||
in a :ref:`local plugin <localplugin>` to make it available also to other
|
||||
test modules::
|
||||
|
||||
# content of conftest.py
|
||||
|
||||
from .remoteinterpreter import RemoteInterpreter
|
||||
|
||||
@pytest.fixture
|
||||
def interp(request):
|
||||
import execnet
|
||||
gw = execnet.makegateway()
|
||||
return RemoteInterpreter(gw)
|
||||
|
||||
To run the example we furthermore need to implement a RemoteInterpreter
|
||||
object which working with the injected execnet-gateway connection::
|
||||
|
||||
# content of remoteintepreter.py
|
||||
|
||||
class RemoteInterpreter:
|
||||
def __init__(self, gateway):
|
||||
self.gateway = gateway
|
||||
|
||||
def eval(self, expression):
|
||||
# execnet open a "gateway" to the remote process
|
||||
# which enables to remotely execute code and communicate
|
||||
# to and fro via channels
|
||||
ch = self.gateway.remote_exec("channel.send(%s)" % expression)
|
||||
return ch.receive()
|
||||
|
||||
That's it, we can now run the test::
|
||||
|
||||
$ py.test test_remoteinterpreter.py
|
||||
Traceback (most recent call last):
|
||||
File "/home/hpk/p/pytest/.tox/regen/bin/py.test", line 9, in <module>
|
||||
load_entry_point('pytest==2.3.0', 'console_scripts', 'py.test')()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 473, in main
|
||||
config = _prepareconfig(args, plugins)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 463, in _prepareconfig
|
||||
pluginmanager=_pluginmanager, args=args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 422, in __call__
|
||||
return self._docall(methods, kwargs)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 433, in _docall
|
||||
res = mc.execute()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 351, in execute
|
||||
res = method(**kwargs)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/helpconfig.py", line 25, in pytest_cmdline_parse
|
||||
config = __multicall__.execute()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 351, in execute
|
||||
res = method(**kwargs)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 10, in pytest_cmdline_parse
|
||||
config.parse(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 344, in parse
|
||||
self._preparse(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 322, in _preparse
|
||||
self._setinitialconftest(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 301, in _setinitialconftest
|
||||
self._conftest.setinitial(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 160, in setinitial
|
||||
self._try_load_conftest(anchor)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 166, in _try_load_conftest
|
||||
self._path2confmods[None] = self.getconftestmodules(anchor)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 190, in getconftestmodules
|
||||
clist[:0] = self.getconftestmodules(dp)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 189, in getconftestmodules
|
||||
clist.append(self.importconftest(conftestpath))
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 218, in importconftest
|
||||
self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/py/_path/local.py", line 532, in pyimport
|
||||
__import__(modname)
|
||||
File "/tmp/doc-exec-286/conftest.py", line 2, in <module>
|
||||
from .remoteinterpreter import RemoteInterpreter
|
||||
ValueError: Attempted relative import in non-package
|
||||
|
||||
.. _`tut-cmdlineoption`:
|
||||
|
||||
Step 2: Adding command line configuration
|
||||
-----------------------------------------------------------
|
||||
|
||||
To add a command line option we update the ``conftest.py`` of
|
||||
the previous example and add a command line option which
|
||||
is passed on to the MyApp object::
|
||||
|
||||
# content of ./conftest.py
|
||||
import pytest
|
||||
from myapp import MyApp
|
||||
|
||||
def pytest_addoption(parser): # pytest hook called during initialisation
|
||||
parser.addoption("--ssh", action="store", default=None,
|
||||
help="specify ssh host to run tests with")
|
||||
|
||||
@pytest.fixture
|
||||
def mysetup(request): # "mysetup" factory function
|
||||
return MySetup(request.config)
|
||||
|
||||
class MySetup:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.app = MyApp()
|
||||
|
||||
def getsshconnection(self):
|
||||
import execnet
|
||||
host = self.config.option.ssh
|
||||
if host is None:
|
||||
pytest.skip("specify ssh host with --ssh")
|
||||
return execnet.SshGateway(host)
|
||||
|
||||
|
||||
Now any test function can use the ``mysetup.getsshconnection()`` method
|
||||
like this::
|
||||
|
||||
# content of test_ssh.py
|
||||
class TestClass:
|
||||
def test_function(self, mysetup):
|
||||
conn = mysetup.getsshconnection()
|
||||
# work with conn
|
||||
|
||||
Running it yields::
|
||||
|
||||
$ py.test -q test_ssh.py -rs
|
||||
Traceback (most recent call last):
|
||||
File "/home/hpk/p/pytest/.tox/regen/bin/py.test", line 9, in <module>
|
||||
load_entry_point('pytest==2.3.0', 'console_scripts', 'py.test')()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 473, in main
|
||||
config = _prepareconfig(args, plugins)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 463, in _prepareconfig
|
||||
pluginmanager=_pluginmanager, args=args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 422, in __call__
|
||||
return self._docall(methods, kwargs)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 433, in _docall
|
||||
res = mc.execute()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 351, in execute
|
||||
res = method(**kwargs)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/helpconfig.py", line 25, in pytest_cmdline_parse
|
||||
config = __multicall__.execute()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/core.py", line 351, in execute
|
||||
res = method(**kwargs)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 10, in pytest_cmdline_parse
|
||||
config.parse(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 344, in parse
|
||||
self._preparse(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 322, in _preparse
|
||||
self._setinitialconftest(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 301, in _setinitialconftest
|
||||
self._conftest.setinitial(args)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 160, in setinitial
|
||||
self._try_load_conftest(anchor)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 166, in _try_load_conftest
|
||||
self._path2confmods[None] = self.getconftestmodules(anchor)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 190, in getconftestmodules
|
||||
clist[:0] = self.getconftestmodules(dp)
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 189, in getconftestmodules
|
||||
clist.append(self.importconftest(conftestpath))
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/config.py", line 218, in importconftest
|
||||
self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport()
|
||||
File "/home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/py/_path/local.py", line 532, in pyimport
|
||||
__import__(modname)
|
||||
File "/tmp/doc-exec-286/conftest.py", line 2, in <module>
|
||||
from myapp import MyApp
|
||||
ImportError: No module named myapp
|
||||
|
||||
If you specify a command line option like ``py.test --ssh=python.org`` the test will execute as expected.
|
||||
|
||||
Note that neither the ``TestClass`` nor the ``test_function`` need to
|
||||
know anything about how to setup the test state. It is handled separately
|
||||
in the ``conftest.py`` file. It is easy
|
||||
to extend the ``mysetup`` object for further needs in the test code - and for use by any other test functions in the files and directories below the ``conftest.py`` file.
|
||||
|
||||
@@ -5,16 +5,22 @@ Usages and Examples
|
||||
===========================================
|
||||
|
||||
Here is a (growing) list of examples. :ref:`Contact <contact>` us if you
|
||||
need more examples or have questions. Also take a look at the :ref:`comprehensive documentation <toc>` which contains many example snippets as well.
|
||||
need more examples or have questions. Also take a look at the
|
||||
:ref:`comprehensive documentation <toc>` which contains many example
|
||||
snippets as well. Also, `pytest on stackoverflow.com
|
||||
<http://stackoverflow.com/search?q=pytest>`_ often comes with example
|
||||
answers.
|
||||
|
||||
Also, `pytest on stackoverflow.com <http://stackoverflow.com/search?q=pytest>`_
|
||||
is a primary continously updated source of pytest questions and answers
|
||||
which often contain examples. New Questions will usually be seen
|
||||
by pytest users or developers.
|
||||
For basic examples, see
|
||||
|
||||
.. note::
|
||||
- :doc:`../getting-started` for basic introductory examples
|
||||
- :ref:`assert` for basic assertion examples
|
||||
- :ref:`fixtures` for basic fixture/setup examples
|
||||
- :ref:`parametrize` for basic test function parametrization
|
||||
- :doc:`../unittest` for basic unittest integration
|
||||
- :doc:`../nose` for basic nosetests integration
|
||||
|
||||
see :doc:`../getting-started` for basic introductory examples
|
||||
The following examples aim at various use cases you might encounter.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
@@ -26,7 +26,7 @@ You can then restrict a test run to only run tests marked with ``webtest``::
|
||||
|
||||
$ py.test -v -m webtest
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_server.py:3: test_send_http PASSED
|
||||
@@ -38,7 +38,7 @@ Or the inverse, running all tests except the webtest ones::
|
||||
|
||||
$ py.test -v -m "not webtest"
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_server.py:6: test_something_quick PASSED
|
||||
@@ -65,13 +65,13 @@ You can ask which markers exist for your test suite - the list includes our just
|
||||
$ py.test --markers
|
||||
@pytest.mark.webtest: mark a test as a webtest.
|
||||
|
||||
@pytest.mark.skipif(*conditions): skip the given test function if evaluation of all conditions has a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform.
|
||||
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html
|
||||
|
||||
@pytest.mark.xfail(*conditions, reason=None, run=True): mark the the test function as an expected failure. Optionally specify a reason and run=False if you don't even want to execute the test function. Any positional condition strings will be evaluated (like with skipif) and if one is False the marker will not be applied.
|
||||
@pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html
|
||||
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in multiple different argument value sets. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in multiple different argument value sets. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2. see http://pytest.org/latest/parametrize.html for more info and examples.
|
||||
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures.
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures
|
||||
|
||||
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.
|
||||
|
||||
@@ -145,7 +145,7 @@ the given argument::
|
||||
|
||||
$ py.test -k send_http # running with the above defined examples
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_server.py .
|
||||
@@ -157,7 +157,7 @@ And you can also run all tests except the ones that match the keyword::
|
||||
|
||||
$ py.test -k-send_http
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_mark_classlevel.py ..
|
||||
@@ -170,7 +170,7 @@ Or to only select the class::
|
||||
|
||||
$ py.test -kTestClass
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_mark_classlevel.py ..
|
||||
@@ -223,7 +223,7 @@ the test needs::
|
||||
|
||||
$ py.test -E stage2
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_someenv.py s
|
||||
@@ -234,25 +234,25 @@ and here is one that specifies exactly the environment needed::
|
||||
|
||||
$ py.test -E stage1
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_someenv.py .
|
||||
|
||||
========================= 1 passed in 0.01 seconds =========================
|
||||
========================= 1 passed in 0.00 seconds =========================
|
||||
|
||||
The ``--markers`` option always gives you a list of available markers::
|
||||
|
||||
$ py.test --markers
|
||||
@pytest.mark.env(name): mark test to run only on named environment
|
||||
|
||||
@pytest.mark.skipif(*conditions): skip the given test function if evaluation of all conditions has a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform.
|
||||
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html
|
||||
|
||||
@pytest.mark.xfail(*conditions, reason=None, run=True): mark the the test function as an expected failure. Optionally specify a reason and run=False if you don't even want to execute the test function. Any positional condition strings will be evaluated (like with skipif) and if one is False the marker will not be applied.
|
||||
@pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html
|
||||
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in multiple different argument value sets. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in multiple different argument value sets. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2. see http://pytest.org/latest/parametrize.html for more info and examples.
|
||||
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures.
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures
|
||||
|
||||
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.
|
||||
|
||||
@@ -351,12 +351,12 @@ then you will see two test skipped and two executed tests as expected::
|
||||
|
||||
$ py.test -rs # this option reports skip reasons
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_plat.py s.s.
|
||||
========================= short test summary info ==========================
|
||||
SKIP [2] /tmp/doc-exec-288/conftest.py:12: cannot run on platform linux2
|
||||
SKIP [2] /tmp/doc-exec-592/conftest.py:12: cannot run on platform linux2
|
||||
|
||||
=================== 2 passed, 2 skipped in 0.01 seconds ====================
|
||||
|
||||
@@ -364,7 +364,7 @@ Note that if you specify a platform via the marker-command line option like this
|
||||
|
||||
$ py.test -m linux2
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_plat.py .
|
||||
|
||||
@@ -27,7 +27,7 @@ now execute the test specification::
|
||||
|
||||
nonpython $ py.test test_simple.yml
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
|
||||
test_simple.yml .F
|
||||
@@ -56,7 +56,7 @@ consulted when reporting in ``verbose`` mode::
|
||||
|
||||
nonpython $ py.test -v
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_simple.yml:1: usecase: ok PASSED
|
||||
@@ -74,10 +74,10 @@ interesting to just look at the collection tree::
|
||||
|
||||
nonpython $ py.test --collectonly
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
<YamlFile 'test_simple.yml'>
|
||||
<YamlItem 'ok'>
|
||||
<YamlItem 'hello'>
|
||||
|
||||
============================= in 0.03 seconds =============================
|
||||
============================= in 0.02 seconds =============================
|
||||
|
||||
@@ -104,7 +104,7 @@ this is a fully self-contained example which you can run with::
|
||||
|
||||
$ py.test test_scenarios.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_scenarios.py ....
|
||||
@@ -116,7 +116,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
|
||||
|
||||
$ py.test --collectonly test_scenarios.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
<Module 'test_scenarios.py'>
|
||||
<Class 'TestSampleWithScenarios'>
|
||||
@@ -180,7 +180,7 @@ Let's first see how it looks like at collection time::
|
||||
|
||||
$ py.test test_backends.py --collectonly
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
<Module 'test_backends.py'>
|
||||
<Function 'test_db_initialized[d1]'>
|
||||
@@ -195,7 +195,7 @@ And then when we run the test::
|
||||
================================= FAILURES =================================
|
||||
_________________________ test_db_initialized[d2] __________________________
|
||||
|
||||
db = <conftest.DB2 instance at 0x2928878>
|
||||
db = <conftest.DB2 instance at 0x233e8c0>
|
||||
|
||||
def test_db_initialized(db):
|
||||
# a dummy test
|
||||
@@ -250,7 +250,7 @@ argument sets to use for each test function. Let's run it::
|
||||
================================= FAILURES =================================
|
||||
________________________ TestClass.test_equals[1-2] ________________________
|
||||
|
||||
self = <test_parametrize.TestClass instance at 0x18dd4d0>, a = 1, b = 2
|
||||
self = <test_parametrize.TestClass instance at 0x2a73518>, a = 1, b = 2
|
||||
|
||||
def test_equals(self, a, b):
|
||||
> assert a == b
|
||||
|
||||
@@ -43,7 +43,7 @@ then the test collection looks like this::
|
||||
|
||||
$ py.test --collectonly
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
<Module 'check_myapp.py'>
|
||||
<Class 'CheckMyApp'>
|
||||
@@ -82,7 +82,7 @@ You can always peek at the collection tree without running tests like this::
|
||||
|
||||
. $ py.test --collectonly pythoncollection.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 3 items
|
||||
<Module 'pythoncollection.py'>
|
||||
<Function 'test_function'>
|
||||
@@ -135,7 +135,7 @@ interpreters and will leave out the setup.py file::
|
||||
|
||||
$ py.test --collectonly
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
<Module 'pkg/module_py2.py'>
|
||||
<Function 'test_only_on_python2'>
|
||||
|
||||
@@ -13,7 +13,7 @@ get on the terminal - we are working on that):
|
||||
|
||||
assertion $ py.test failure_demo.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 39 items
|
||||
|
||||
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
@@ -30,7 +30,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:15: AssertionError
|
||||
_________________________ TestFailing.test_simple __________________________
|
||||
|
||||
self = <failure_demo.TestFailing object at 0x2727750>
|
||||
self = <failure_demo.TestFailing object at 0x27ee810>
|
||||
|
||||
def test_simple(self):
|
||||
def f():
|
||||
@@ -40,13 +40,13 @@ get on the terminal - we are working on that):
|
||||
|
||||
> assert f() == g()
|
||||
E assert 42 == 43
|
||||
E + where 42 = <function f at 0x26cf488>()
|
||||
E + and 43 = <function g at 0x26cf500>()
|
||||
E + where 42 = <function f at 0x2786488>()
|
||||
E + and 43 = <function g at 0x2786500>()
|
||||
|
||||
failure_demo.py:28: AssertionError
|
||||
____________________ TestFailing.test_simple_multiline _____________________
|
||||
|
||||
self = <failure_demo.TestFailing object at 0x27277d0>
|
||||
self = <failure_demo.TestFailing object at 0x27ee890>
|
||||
|
||||
def test_simple_multiline(self):
|
||||
otherfunc_multi(
|
||||
@@ -66,19 +66,19 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:11: AssertionError
|
||||
___________________________ TestFailing.test_not ___________________________
|
||||
|
||||
self = <failure_demo.TestFailing object at 0x2727890>
|
||||
self = <failure_demo.TestFailing object at 0x27eea50>
|
||||
|
||||
def test_not(self):
|
||||
def f():
|
||||
return 42
|
||||
> assert not f()
|
||||
E assert not 42
|
||||
E + where 42 = <function f at 0x26cf7d0>()
|
||||
E + where 42 = <function f at 0x27867d0>()
|
||||
|
||||
failure_demo.py:38: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_text _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x2727c10>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x27ee9d0>
|
||||
|
||||
def test_eq_text(self):
|
||||
> assert 'spam' == 'eggs'
|
||||
@@ -89,7 +89,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:42: AssertionError
|
||||
_____________ TestSpecialisedExplanations.test_eq_similar_text _____________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26d1110>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x27961d0>
|
||||
|
||||
def test_eq_similar_text(self):
|
||||
> assert 'foo 1 bar' == 'foo 2 bar'
|
||||
@@ -102,7 +102,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:45: AssertionError
|
||||
____________ TestSpecialisedExplanations.test_eq_multiline_text ____________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26d1190>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x2796250>
|
||||
|
||||
def test_eq_multiline_text(self):
|
||||
> assert 'foo\nspam\nbar' == 'foo\neggs\nbar'
|
||||
@@ -115,7 +115,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:48: AssertionError
|
||||
______________ TestSpecialisedExplanations.test_eq_long_text _______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26d1090>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x2796090>
|
||||
|
||||
def test_eq_long_text(self):
|
||||
a = '1'*100 + 'a' + '2'*100
|
||||
@@ -132,7 +132,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:53: AssertionError
|
||||
_________ TestSpecialisedExplanations.test_eq_long_text_multiline __________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c7ed0>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x278cf50>
|
||||
|
||||
def test_eq_long_text_multiline(self):
|
||||
a = '1\n'*100 + 'a' + '2\n'*100
|
||||
@@ -156,7 +156,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:58: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_list _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c7190>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x278c250>
|
||||
|
||||
def test_eq_list(self):
|
||||
> assert [0, 1, 2] == [0, 1, 3]
|
||||
@@ -166,7 +166,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:61: AssertionError
|
||||
______________ TestSpecialisedExplanations.test_eq_list_long _______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c7410>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x278c4d0>
|
||||
|
||||
def test_eq_list_long(self):
|
||||
a = [0]*100 + [1] + [3]*100
|
||||
@@ -178,7 +178,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:66: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_dict _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c78d0>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x278cbd0>
|
||||
|
||||
def test_eq_dict(self):
|
||||
> assert {'a': 0, 'b': 1} == {'a': 0, 'b': 2}
|
||||
@@ -191,7 +191,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:69: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_set __________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c7690>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x278c750>
|
||||
|
||||
def test_eq_set(self):
|
||||
> assert set([0, 10, 11, 12]) == set([0, 20, 21])
|
||||
@@ -207,7 +207,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:72: AssertionError
|
||||
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c7510>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x278c5d0>
|
||||
|
||||
def test_eq_longer_list(self):
|
||||
> assert [1,2] == [1,2,3]
|
||||
@@ -217,7 +217,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:75: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_in_list _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c3190>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x27880d0>
|
||||
|
||||
def test_in_list(self):
|
||||
> assert 1 in [0, 2, 3, 4, 5]
|
||||
@@ -226,7 +226,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:78: AssertionError
|
||||
__________ TestSpecialisedExplanations.test_not_in_text_multiline __________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c3d10>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x2788ed0>
|
||||
|
||||
def test_not_in_text_multiline(self):
|
||||
text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail'
|
||||
@@ -244,7 +244,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:82: AssertionError
|
||||
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c3d50>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x2788fd0>
|
||||
|
||||
def test_not_in_text_single(self):
|
||||
text = 'single foo line'
|
||||
@@ -257,7 +257,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:86: AssertionError
|
||||
_________ TestSpecialisedExplanations.test_not_in_text_single_long _________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c3790>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x2788850>
|
||||
|
||||
def test_not_in_text_single_long(self):
|
||||
text = 'head ' * 50 + 'foo ' + 'tail ' * 20
|
||||
@@ -270,7 +270,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:90: AssertionError
|
||||
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x26c3150>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0x27882d0>
|
||||
|
||||
def test_not_in_text_single_long_term(self):
|
||||
text = 'head ' * 50 + 'f'*70 + 'tail ' * 20
|
||||
@@ -289,7 +289,7 @@ get on the terminal - we are working on that):
|
||||
i = Foo()
|
||||
> assert i.b == 2
|
||||
E assert 1 == 2
|
||||
E + where 1 = <failure_demo.Foo object at 0x26c3850>.b
|
||||
E + where 1 = <failure_demo.Foo object at 0x2788910>.b
|
||||
|
||||
failure_demo.py:101: AssertionError
|
||||
_________________________ test_attribute_instance __________________________
|
||||
@@ -299,8 +299,8 @@ get on the terminal - we are working on that):
|
||||
b = 1
|
||||
> assert Foo().b == 2
|
||||
E assert 1 == 2
|
||||
E + where 1 = <failure_demo.Foo object at 0x26c39d0>.b
|
||||
E + where <failure_demo.Foo object at 0x26c39d0> = <class 'failure_demo.Foo'>()
|
||||
E + where 1 = <failure_demo.Foo object at 0x2788f50>.b
|
||||
E + where <failure_demo.Foo object at 0x2788f50> = <class 'failure_demo.Foo'>()
|
||||
|
||||
failure_demo.py:107: AssertionError
|
||||
__________________________ test_attribute_failure __________________________
|
||||
@@ -316,7 +316,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:116:
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|
||||
self = <failure_demo.Foo object at 0x2890810>
|
||||
self = <failure_demo.Foo object at 0x29558d0>
|
||||
|
||||
def _get_b(self):
|
||||
> raise Exception('Failed to get attrib')
|
||||
@@ -332,15 +332,15 @@ get on the terminal - we are working on that):
|
||||
b = 2
|
||||
> assert Foo().b == Bar().b
|
||||
E assert 1 == 2
|
||||
E + where 1 = <failure_demo.Foo object at 0x26c35d0>.b
|
||||
E + where <failure_demo.Foo object at 0x26c35d0> = <class 'failure_demo.Foo'>()
|
||||
E + and 2 = <failure_demo.Bar object at 0x26c3c50>.b
|
||||
E + where <failure_demo.Bar object at 0x26c3c50> = <class 'failure_demo.Bar'>()
|
||||
E + where 1 = <failure_demo.Foo object at 0x2788690>.b
|
||||
E + where <failure_demo.Foo object at 0x2788690> = <class 'failure_demo.Foo'>()
|
||||
E + and 2 = <failure_demo.Bar object at 0x2788d10>.b
|
||||
E + where <failure_demo.Bar object at 0x2788d10> = <class 'failure_demo.Bar'>()
|
||||
|
||||
failure_demo.py:124: AssertionError
|
||||
__________________________ TestRaises.test_raises __________________________
|
||||
|
||||
self = <failure_demo.TestRaises instance at 0x2738c68>
|
||||
self = <failure_demo.TestRaises instance at 0x28000e0>
|
||||
|
||||
def test_raises(self):
|
||||
s = 'qwe'
|
||||
@@ -352,10 +352,10 @@ get on the terminal - we are working on that):
|
||||
> int(s)
|
||||
E ValueError: invalid literal for int() with base 10: 'qwe'
|
||||
|
||||
<0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:838>:1: ValueError
|
||||
<0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:850>:1: ValueError
|
||||
______________________ TestRaises.test_raises_doesnt _______________________
|
||||
|
||||
self = <failure_demo.TestRaises instance at 0x27413b0>
|
||||
self = <failure_demo.TestRaises instance at 0x2806b90>
|
||||
|
||||
def test_raises_doesnt(self):
|
||||
> raises(IOError, "int('3')")
|
||||
@@ -364,7 +364,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:136: Failed
|
||||
__________________________ TestRaises.test_raise ___________________________
|
||||
|
||||
self = <failure_demo.TestRaises instance at 0x273a4d0>
|
||||
self = <failure_demo.TestRaises instance at 0x27ff518>
|
||||
|
||||
def test_raise(self):
|
||||
> raise ValueError("demo error")
|
||||
@@ -373,7 +373,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:139: ValueError
|
||||
________________________ TestRaises.test_tupleerror ________________________
|
||||
|
||||
self = <failure_demo.TestRaises instance at 0x272d248>
|
||||
self = <failure_demo.TestRaises instance at 0x27f2290>
|
||||
|
||||
def test_tupleerror(self):
|
||||
> a,b = [1]
|
||||
@@ -382,7 +382,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:142: ValueError
|
||||
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
|
||||
|
||||
self = <failure_demo.TestRaises instance at 0x272df80>
|
||||
self = <failure_demo.TestRaises instance at 0x27f2fc8>
|
||||
|
||||
def test_reinterpret_fails_with_print_for_the_fun_of_it(self):
|
||||
l = [1,2,3]
|
||||
@@ -395,7 +395,7 @@ get on the terminal - we are working on that):
|
||||
l is [1, 2, 3]
|
||||
________________________ TestRaises.test_some_error ________________________
|
||||
|
||||
self = <failure_demo.TestRaises instance at 0x272ed88>
|
||||
self = <failure_demo.TestRaises instance at 0x27f3dd0>
|
||||
|
||||
def test_some_error(self):
|
||||
> if namenotexi:
|
||||
@@ -423,7 +423,7 @@ get on the terminal - we are working on that):
|
||||
<2-codegen 'abc-123' /home/hpk/p/pytest/doc/en/example/assertion/failure_demo.py:162>:2: AssertionError
|
||||
____________________ TestMoreErrors.test_complex_error _____________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x2741758>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x28067a0>
|
||||
|
||||
def test_complex_error(self):
|
||||
def f():
|
||||
@@ -452,7 +452,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:5: AssertionError
|
||||
___________________ TestMoreErrors.test_z1_unpack_error ____________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x2728d88>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27eddd0>
|
||||
|
||||
def test_z1_unpack_error(self):
|
||||
l = []
|
||||
@@ -462,7 +462,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:179: ValueError
|
||||
____________________ TestMoreErrors.test_z2_type_error _____________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x272ab90>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27efbd8>
|
||||
|
||||
def test_z2_type_error(self):
|
||||
l = 3
|
||||
@@ -472,19 +472,19 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:183: TypeError
|
||||
______________________ TestMoreErrors.test_startswith ______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x272b998>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27f09e0>
|
||||
|
||||
def test_startswith(self):
|
||||
s = "123"
|
||||
g = "456"
|
||||
> assert s.startswith(g)
|
||||
E assert <built-in method startswith of str object at 0x2734ad0>('456')
|
||||
E + where <built-in method startswith of str object at 0x2734ad0> = '123'.startswith
|
||||
E assert <built-in method startswith of str object at 0x27f9ad0>('456')
|
||||
E + where <built-in method startswith of str object at 0x27f9ad0> = '123'.startswith
|
||||
|
||||
failure_demo.py:188: AssertionError
|
||||
__________________ TestMoreErrors.test_startswith_nested ___________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x272a0e0>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27ef098>
|
||||
|
||||
def test_startswith_nested(self):
|
||||
def f():
|
||||
@@ -492,15 +492,15 @@ get on the terminal - we are working on that):
|
||||
def g():
|
||||
return "456"
|
||||
> assert f().startswith(g())
|
||||
E assert <built-in method startswith of str object at 0x2734ad0>('456')
|
||||
E + where <built-in method startswith of str object at 0x2734ad0> = '123'.startswith
|
||||
E + where '123' = <function f at 0x27549b0>()
|
||||
E + and '456' = <function g at 0x27488c0>()
|
||||
E assert <built-in method startswith of str object at 0x27f9ad0>('456')
|
||||
E + where <built-in method startswith of str object at 0x27f9ad0> = '123'.startswith
|
||||
E + where '123' = <function f at 0x28169b0>()
|
||||
E + and '456' = <function g at 0x280e8c0>()
|
||||
|
||||
failure_demo.py:195: AssertionError
|
||||
_____________________ TestMoreErrors.test_global_func ______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x273b7a0>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x2800878>
|
||||
|
||||
def test_global_func(self):
|
||||
> assert isinstance(globf(42), float)
|
||||
@@ -510,18 +510,18 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:198: AssertionError
|
||||
_______________________ TestMoreErrors.test_instance _______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x272dd88>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27f20e0>
|
||||
|
||||
def test_instance(self):
|
||||
self.x = 6*7
|
||||
> assert self.x != 42
|
||||
E assert 42 != 42
|
||||
E + where 42 = <failure_demo.TestMoreErrors instance at 0x272dd88>.x
|
||||
E + where 42 = <failure_demo.TestMoreErrors instance at 0x27f20e0>.x
|
||||
|
||||
failure_demo.py:202: AssertionError
|
||||
_______________________ TestMoreErrors.test_compare ________________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x2729560>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27ec5a8>
|
||||
|
||||
def test_compare(self):
|
||||
> assert globf(10) < 5
|
||||
@@ -531,7 +531,7 @@ get on the terminal - we are working on that):
|
||||
failure_demo.py:205: AssertionError
|
||||
_____________________ TestMoreErrors.test_try_finally ______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors instance at 0x271f3b0>
|
||||
self = <failure_demo.TestMoreErrors instance at 0x27e43b0>
|
||||
|
||||
def test_try_finally(self):
|
||||
x = 1
|
||||
@@ -540,4 +540,4 @@ get on the terminal - we are working on that):
|
||||
E assert 1 == 0
|
||||
|
||||
failure_demo.py:210: AssertionError
|
||||
======================== 39 failed in 0.18 seconds =========================
|
||||
======================== 39 failed in 0.16 seconds =========================
|
||||
|
||||
@@ -106,7 +106,7 @@ directory with the above conftest.py::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 0 items
|
||||
|
||||
============================= in 0.00 seconds =============================
|
||||
@@ -150,12 +150,12 @@ and when running it will see a skipped "slow" test::
|
||||
|
||||
$ py.test -rs # "-rs" means report details on the little 's'
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
|
||||
test_module.py .s
|
||||
========================= short test summary info ==========================
|
||||
SKIP [1] /tmp/doc-exec-293/conftest.py:9: need --runslow option to run
|
||||
SKIP [1] /tmp/doc-exec-597/conftest.py:9: need --runslow option to run
|
||||
|
||||
=================== 1 passed, 1 skipped in 0.01 seconds ====================
|
||||
|
||||
@@ -163,7 +163,7 @@ Or run it including the ``slow`` marked test::
|
||||
|
||||
$ py.test --runslow
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
|
||||
test_module.py ..
|
||||
@@ -253,7 +253,7 @@ which will add the string to the test header accordingly::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
project deps: mylib-1.1
|
||||
collected 0 items
|
||||
|
||||
@@ -276,7 +276,7 @@ which will add info only when run with "--v"::
|
||||
|
||||
$ py.test -v
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
info1: did you know that ...
|
||||
did you?
|
||||
collecting ... collected 0 items
|
||||
@@ -287,7 +287,7 @@ and nothing when run plainly::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 0 items
|
||||
|
||||
============================= in 0.00 seconds =============================
|
||||
@@ -319,7 +319,7 @@ Now we can profile which test functions execute the slowest::
|
||||
|
||||
$ py.test --durations=3
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 3 items
|
||||
|
||||
test_some_are_slow.py ...
|
||||
@@ -380,7 +380,7 @@ If we run this::
|
||||
|
||||
$ py.test -rx
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 4 items
|
||||
|
||||
test_step.py .Fx.
|
||||
@@ -388,7 +388,7 @@ If we run this::
|
||||
================================= FAILURES =================================
|
||||
____________________ TestUserHandling.test_modification ____________________
|
||||
|
||||
self = <test_step.TestUserHandling instance at 0x1db2638>
|
||||
self = <test_step.TestUserHandling instance at 0x1aad680>
|
||||
|
||||
def test_modification(self):
|
||||
> assert 0
|
||||
|
||||
@@ -26,8 +26,9 @@ functions:
|
||||
fixtures.
|
||||
|
||||
* fixture management scales from simple unit to complex
|
||||
functional testing, allowing to parametrize fixtures or tests according
|
||||
to configuration and component options.
|
||||
functional testing, allowing to parametrize fixtures and tests according
|
||||
to configuration and component options, or to re-use fixtures
|
||||
across class, module or whole test session scopes.
|
||||
|
||||
In addition, pytest continues to support :ref:`xunitsetup` which it
|
||||
originally introduced in 2005. You can mix both styles, moving
|
||||
@@ -47,7 +48,7 @@ Fixtures as Function arguments (funcargs)
|
||||
Test functions can receive fixture objects by naming them as an input
|
||||
argument. For each argument name, a fixture function with that name provides
|
||||
the fixture object. Fixture functions are registered by marking them with
|
||||
:py:func:`@pytest.fixture <pytest.fixture>`. Let's look at a simple
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>`. Let's look at a simple
|
||||
self-contained test module containing a fixture and a test function
|
||||
using it::
|
||||
|
||||
@@ -66,12 +67,12 @@ using it::
|
||||
assert 0 # for demo purposes
|
||||
|
||||
Here, the ``test_function`` needs the ``smtp`` fixture value. pytest
|
||||
will discover and call the ``@pytest.fixture`` marked ``smtp``
|
||||
fixture function. Running the test looks like this::
|
||||
will discover and call the :py:func:`@pytest.fixture <_pytest.python.fixture>`
|
||||
marked ``smtp`` fixture function. Running the test looks like this::
|
||||
|
||||
$ py.test test_smtpsimple.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_smtpsimple.py F
|
||||
@@ -79,7 +80,7 @@ fixture function. Running the test looks like this::
|
||||
================================= FAILURES =================================
|
||||
________________________________ test_ehlo _________________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x1eade18>
|
||||
smtp = <smtplib.SMTP instance at 0x1ab68c0>
|
||||
|
||||
def test_ehlo(smtp):
|
||||
response, msg = smtp.ehlo()
|
||||
@@ -89,7 +90,7 @@ fixture function. Running the test looks like this::
|
||||
E assert 0
|
||||
|
||||
test_smtpsimple.py:12: AssertionError
|
||||
========================= 1 failed in 0.20 seconds =========================
|
||||
========================= 1 failed in 0.12 seconds =========================
|
||||
|
||||
In the failure traceback we see that the test function was called with a
|
||||
``smtp`` argument, the ``smtplib.SMTP()`` instance created by the fixture
|
||||
@@ -143,25 +144,27 @@ functions take the role of the *injector* and test functions are the
|
||||
|
||||
.. _smtpshared:
|
||||
|
||||
Working with a session-shared fixture
|
||||
Working with a module-shared fixture
|
||||
-----------------------------------------------------------------
|
||||
|
||||
.. regendoc:wipe
|
||||
|
||||
Fixtures requiring network access depend on connectivity and are
|
||||
usually time-expensive to create. Extending the previous example, we
|
||||
can add a ``scope='session'`` parameter to ``@pytest.fixture`` decorator.
|
||||
can add a ``scope='module'`` parameter to the
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>` invocation
|
||||
to cause the decorated ``smtp`` fixture function to only be invoked once
|
||||
per test session. Multiple test functions will thus each receive the
|
||||
same ``smtp`` fixture instance. The next example also extracts
|
||||
the fixture function into a separate ``conftest.py`` file so that
|
||||
all tests in the directory can access the fixture function::
|
||||
per test module. Multiple test functions in a test module will thus
|
||||
each receive the same ``smtp`` fixture instance. The next example also
|
||||
extracts the fixture function into a separate ``conftest.py`` file so
|
||||
that all tests in test modules in the directory can access the fixture
|
||||
function::
|
||||
|
||||
# content of conftest.py
|
||||
import pytest
|
||||
import smtplib
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@pytest.fixture(scope="module")
|
||||
def smtp():
|
||||
return smtplib.SMTP("merlinux.eu")
|
||||
|
||||
@@ -187,7 +190,7 @@ inspect what is going on and can now run the tests::
|
||||
|
||||
$ py.test test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
|
||||
test_module.py FF
|
||||
@@ -195,7 +198,7 @@ inspect what is going on and can now run the tests::
|
||||
================================= FAILURES =================================
|
||||
________________________________ test_ehlo _________________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x29213b0>
|
||||
smtp = <smtplib.SMTP instance at 0x2c35488>
|
||||
|
||||
def test_ehlo(smtp):
|
||||
response = smtp.ehlo()
|
||||
@@ -207,7 +210,7 @@ inspect what is going on and can now run the tests::
|
||||
test_module.py:6: AssertionError
|
||||
________________________________ test_noop _________________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x29213b0>
|
||||
smtp = <smtplib.SMTP instance at 0x2c35488>
|
||||
|
||||
def test_noop(smtp):
|
||||
response = smtp.noop()
|
||||
@@ -216,28 +219,39 @@ inspect what is going on and can now run the tests::
|
||||
E assert 0
|
||||
|
||||
test_module.py:11: AssertionError
|
||||
========================= 2 failed in 0.20 seconds =========================
|
||||
========================= 2 failed in 0.13 seconds =========================
|
||||
|
||||
You see the two ``assert 0`` failing and more importantly you can also see
|
||||
that the same (session-scoped) ``smtp`` object was passed into the two
|
||||
that the same (module-scoped) ``smtp`` object was passed into the two
|
||||
test functions because pytest shows the incoming argument values in the
|
||||
traceback. As a result, the two test functions using ``smtp`` run as
|
||||
quick as a single one because they reuse the same instance.
|
||||
|
||||
If you decide that you rather want to have a session-scoped ``smtp``
|
||||
instance, you can simply declare it::
|
||||
|
||||
@pytest.fixture(scope=``session``)
|
||||
def smtp(...):
|
||||
# the returned fixture value will be shared for
|
||||
# all tests needing it
|
||||
|
||||
.. _`request-context`:
|
||||
|
||||
Fixtures can interact with the requesting test context
|
||||
-------------------------------------------------------------
|
||||
|
||||
Using the special :py:class:`request <FixtureRequest>` argument,
|
||||
fixture functions can introspect the function, class or module for which
|
||||
they are invoked or can register finalizing (cleanup)
|
||||
Fixture functions can themselves use other fixtures by naming
|
||||
them as an input argument just like test functions do, see
|
||||
:ref:`interdependent fixtures`. Moreover, pytest
|
||||
provides a builtin :py:class:`request <FixtureRequest>` object,
|
||||
which fixture functions can use to introspect the function, class or module
|
||||
for which they are invoked or to register finalizing (cleanup)
|
||||
functions which are called when the last test finished execution.
|
||||
|
||||
Further extending the previous ``smtp`` fixture example, let's try to
|
||||
read the server URL from the module namespace, also use module-caching and
|
||||
register a finalizer that closes the smtp connection after the last
|
||||
test finished execution::
|
||||
Further extending the previous ``smtp`` fixture example, let's
|
||||
read an optional server URL from the module namespace and register
|
||||
a finalizer that closes the smtp connection after the last
|
||||
test in a module finished execution::
|
||||
|
||||
# content of conftest.py
|
||||
import pytest
|
||||
@@ -258,12 +272,12 @@ using it has executed::
|
||||
|
||||
$ py.test -s -q --tb=no
|
||||
FF
|
||||
finalizing <smtplib.SMTP instance at 0x1a9d5a8>
|
||||
finalizing <smtplib.SMTP instance at 0x2afd830>
|
||||
|
||||
We see that the ``smtp`` instance is finalized after the two
|
||||
tests using it tests executed. If we had specified ``scope='function'``
|
||||
then fixture setup and cleanup would occur around each single test.
|
||||
Note that the test module itself did not need to change!
|
||||
Note that either case the test module itself does not need to change!
|
||||
|
||||
Let's quickly create another test module that actually sets the
|
||||
server URL and has a test to verify the fixture picks it up::
|
||||
@@ -289,7 +303,7 @@ Running it::
|
||||
|
||||
.. _`fixture-parametrize`:
|
||||
|
||||
Parametrizing a session-shared fixture
|
||||
Parametrizing a fixture
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Fixture functions can be parametrized in which case they will be called
|
||||
@@ -308,7 +322,7 @@ through the special `request`_ object::
|
||||
import pytest
|
||||
import smtplib
|
||||
|
||||
@pytest.fixture(scope="session",
|
||||
@pytest.fixture(scope="module",
|
||||
params=["merlinux.eu", "mail.python.org"])
|
||||
def smtp(request):
|
||||
smtp = smtplib.SMTP(request.param)
|
||||
@@ -318,7 +332,8 @@ through the special `request`_ object::
|
||||
request.addfinalizer(fin)
|
||||
return smtp
|
||||
|
||||
The main change is the declaration of ``params``, a list of values
|
||||
The main change is the declaration of ``params`` with
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values
|
||||
for each of which the fixture function will execute and can access
|
||||
a value via ``request.param``. No test function code needs to change.
|
||||
So let's just do another run::
|
||||
@@ -328,7 +343,7 @@ So let's just do another run::
|
||||
================================= FAILURES =================================
|
||||
__________________________ test_ehlo[merlinux.eu] __________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x1eae680>
|
||||
smtp = <smtplib.SMTP instance at 0x1bd3710>
|
||||
|
||||
def test_ehlo(smtp):
|
||||
response = smtp.ehlo()
|
||||
@@ -340,7 +355,7 @@ So let's just do another run::
|
||||
test_module.py:6: AssertionError
|
||||
__________________________ test_noop[merlinux.eu] __________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x1eae680>
|
||||
smtp = <smtplib.SMTP instance at 0x1bd3710>
|
||||
|
||||
def test_noop(smtp):
|
||||
response = smtp.noop()
|
||||
@@ -351,7 +366,7 @@ So let's just do another run::
|
||||
test_module.py:11: AssertionError
|
||||
________________________ test_ehlo[mail.python.org] ________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x1eb7fc8>
|
||||
smtp = <smtplib.SMTP instance at 0x1c58128>
|
||||
|
||||
def test_ehlo(smtp):
|
||||
response = smtp.ehlo()
|
||||
@@ -362,7 +377,7 @@ So let's just do another run::
|
||||
test_module.py:5: AssertionError
|
||||
________________________ test_noop[mail.python.org] ________________________
|
||||
|
||||
smtp = <smtplib.SMTP instance at 0x1eb7fc8>
|
||||
smtp = <smtplib.SMTP instance at 0x1c58128>
|
||||
|
||||
def test_noop(smtp):
|
||||
response = smtp.noop()
|
||||
@@ -410,21 +425,23 @@ Here we declare an ``app`` fixture which receives the previously defined
|
||||
|
||||
$ py.test -v test_appsetup.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_appsetup.py:12: test_smtp_exists[merlinux.eu] PASSED
|
||||
test_appsetup.py:12: test_smtp_exists[mail.python.org] PASSED
|
||||
|
||||
========================= 2 passed in 0.17 seconds =========================
|
||||
========================= 2 passed in 0.20 seconds =========================
|
||||
|
||||
Due to the parametrization of ``smtp`` the test will run twice with two
|
||||
different ``App`` instances and respective smtp servers. There is no
|
||||
need for the ``app`` fixture to be aware of the ``smtp`` parametrization
|
||||
as pytest will fully analyse the fixture dependency graph. Note also,
|
||||
that the ``app`` fixture has a scope of ``module`` but may use a
|
||||
session-scoped ``smtp`` from the example higher up: it is fine for
|
||||
fixtures to use "broader" scoped fixtures but not the other way round:
|
||||
as pytest will fully analyse the fixture dependency graph.
|
||||
|
||||
Note, that the ``app`` fixture has a scope of ``module`` and uses a
|
||||
module-scoped ``smtp`` fixture. The example would still work if ``smtp``
|
||||
was cached on a ``session`` scope: it is fine for fixtures to use
|
||||
"broader" scoped fixtures but not the other way round:
|
||||
A session-scoped fixture could not use a module-scoped one in a
|
||||
meaningful way.
|
||||
|
||||
@@ -473,7 +490,7 @@ Let's run the tests in verbose mode and with looking at the print-output::
|
||||
|
||||
$ py.test -v -s test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1 -- /home/hpk/p/pytest/.tox/regen/bin/python
|
||||
collecting ... collected 8 items
|
||||
|
||||
test_module.py:16: test_0[1] PASSED
|
||||
|
||||
@@ -23,7 +23,7 @@ Installation options::
|
||||
To check your installation has installed the correct version::
|
||||
|
||||
$ py.test --version
|
||||
This is py.test version 2.3.0, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc
|
||||
This is py.test version 2.3.1, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc
|
||||
|
||||
If you get an error checkout :ref:`installation issues`.
|
||||
|
||||
@@ -45,7 +45,7 @@ That's it. You can execute the test function now::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_sample.py F
|
||||
@@ -122,7 +122,7 @@ run the module by passing its filename::
|
||||
================================= FAILURES =================================
|
||||
____________________________ TestClass.test_two ____________________________
|
||||
|
||||
self = <test_class.TestClass instance at 0x1f8a6c8>
|
||||
self = <test_class.TestClass instance at 0x10de710>
|
||||
|
||||
def test_two(self):
|
||||
x = "hello"
|
||||
@@ -157,7 +157,7 @@ before performing the test function call. Let's just run it::
|
||||
================================= FAILURES =================================
|
||||
_____________________________ test_needsfiles ______________________________
|
||||
|
||||
tmpdir = local('/tmp/pytest-1409/test_needsfiles0')
|
||||
tmpdir = local('/tmp/pytest-1516/test_needsfiles0')
|
||||
|
||||
def test_needsfiles(tmpdir):
|
||||
print tmpdir
|
||||
@@ -166,7 +166,7 @@ before performing the test function call. Let's just run it::
|
||||
|
||||
test_tmpdir.py:3: AssertionError
|
||||
----------------------------- Captured stdout ------------------------------
|
||||
/tmp/pytest-1409/test_needsfiles0
|
||||
/tmp/pytest-1516/test_needsfiles0
|
||||
|
||||
Before the test runs, a unique-per-test-invocation temporary directory
|
||||
was created. More info at :ref:`tmpdir handling`.
|
||||
|
||||
@@ -53,7 +53,7 @@ which will thus run three times::
|
||||
|
||||
$ py.test
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 3 items
|
||||
|
||||
test_expectation.py ..F
|
||||
@@ -135,8 +135,8 @@ Let's also run with a stringinput that will lead to a failing test::
|
||||
|
||||
def test_valid_string(stringinput):
|
||||
> assert stringinput.isalpha()
|
||||
E assert <built-in method isalpha of str object at 0x2b7d7a85a030>()
|
||||
E + where <built-in method isalpha of str object at 0x2b7d7a85a030> = '!'.isalpha
|
||||
E assert <built-in method isalpha of str object at 0x2b21d78ed030>()
|
||||
E + where <built-in method isalpha of str object at 0x2b21d78ed030> = '!'.isalpha
|
||||
|
||||
test_strings.py:3: AssertionError
|
||||
|
||||
@@ -149,7 +149,7 @@ listlist::
|
||||
$ py.test -q -rs test_strings.py
|
||||
s
|
||||
========================= short test summary info ==========================
|
||||
SKIP [1] /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:947: got empty parameter set, function test_valid_string at /tmp/doc-exec-259/test_strings.py:1
|
||||
SKIP [1] /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:959: got empty parameter set, function test_valid_string at /tmp/doc-exec-564/test_strings.py:1
|
||||
|
||||
For further examples, you might want to look at :ref:`more
|
||||
parametrization examples <paramexamples>`.
|
||||
|
||||
@@ -132,7 +132,7 @@ Running it with the report-on-xfail option gives this output::
|
||||
|
||||
example $ py.test -rx xfail_demo.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 6 items
|
||||
|
||||
xfail_demo.py xxxxxx
|
||||
|
||||
@@ -29,7 +29,7 @@ Running this would result in a passed test except for the last
|
||||
|
||||
$ py.test test_tmpdir.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 1 items
|
||||
|
||||
test_tmpdir.py F
|
||||
@@ -37,7 +37,7 @@ Running this would result in a passed test except for the last
|
||||
================================= FAILURES =================================
|
||||
_____________________________ test_create_file _____________________________
|
||||
|
||||
tmpdir = local('/tmp/pytest-1410/test_create_file0')
|
||||
tmpdir = local('/tmp/pytest-1517/test_create_file0')
|
||||
|
||||
def test_create_file(tmpdir):
|
||||
p = tmpdir.mkdir("sub").join("hello.txt")
|
||||
@@ -48,7 +48,7 @@ Running this would result in a passed test except for the last
|
||||
E assert 0
|
||||
|
||||
test_tmpdir.py:7: AssertionError
|
||||
========================= 1 failed in 0.03 seconds =========================
|
||||
========================= 1 failed in 0.04 seconds =========================
|
||||
|
||||
.. _`base temporary directory`:
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ the ``self.db`` values in the traceback::
|
||||
|
||||
$ py.test test_unittest_db.py
|
||||
=========================== test session starts ============================
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.0
|
||||
platform linux2 -- Python 2.7.3 -- pytest-2.3.1
|
||||
collected 2 items
|
||||
|
||||
test_unittest_db.py FF
|
||||
@@ -101,7 +101,7 @@ the ``self.db`` values in the traceback::
|
||||
def test_method1(self):
|
||||
assert hasattr(self, "db")
|
||||
> assert 0, self.db # fail for demo purposes
|
||||
E AssertionError: <conftest.DummyDB instance at 0x2e36bd8>
|
||||
E AssertionError: <conftest.DummyDB instance at 0x25b1998>
|
||||
|
||||
test_unittest_db.py:9: AssertionError
|
||||
___________________________ MyTest.test_method2 ____________________________
|
||||
@@ -110,7 +110,7 @@ the ``self.db`` values in the traceback::
|
||||
|
||||
def test_method2(self):
|
||||
> assert 0, self.db # fail for demo purposes
|
||||
E AssertionError: <conftest.DummyDB instance at 0x2e36bd8>
|
||||
E AssertionError: <conftest.DummyDB instance at 0x25b1998>
|
||||
|
||||
test_unittest_db.py:12: AssertionError
|
||||
========================= 2 failed in 0.02 seconds =========================
|
||||
|
||||
2
setup.py
2
setup.py
@@ -24,7 +24,7 @@ def main():
|
||||
name='pytest',
|
||||
description='py.test: simple powerful testing with Python',
|
||||
long_description = long_description,
|
||||
version='2.3.0',
|
||||
version='2.3.1',
|
||||
url='http://pytest.org',
|
||||
license='MIT license',
|
||||
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
||||
|
||||
@@ -2037,6 +2037,21 @@ class TestFixtureUsages:
|
||||
reprec = testdir.inline_run()
|
||||
reprec.assertoutcome(passed=2)
|
||||
|
||||
def test_request_instance_issue203(self, testdir):
|
||||
testdir.makepyfile("""
|
||||
import pytest
|
||||
|
||||
class TestClass:
|
||||
@pytest.fixture
|
||||
def setup1(self, request):
|
||||
assert self == request.instance
|
||||
self.arg1 = 1
|
||||
def test_hello(self, setup1):
|
||||
assert self.arg1 == 1
|
||||
""")
|
||||
reprec = testdir.inline_run()
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
class TestFixtureManager:
|
||||
def pytest_funcarg__testdir(self, request):
|
||||
testdir = request.getfuncargvalue("testdir")
|
||||
|
||||
@@ -551,8 +551,8 @@ def test_direct_gives_error(testdir):
|
||||
def test_default_markers(testdir):
|
||||
result = testdir.runpytest("--markers")
|
||||
result.stdout.fnmatch_lines([
|
||||
"*skipif(*conditions)*skip*",
|
||||
"*xfail(*conditions, reason=None, run=True)*expected failure*",
|
||||
"*skipif(*condition)*skip*",
|
||||
"*xfail(*condition, reason=None, run=True)*expected failure*",
|
||||
])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user