Compare commits

...

24 Commits
2.3.0 ... 2.3.2

Author SHA1 Message Date
holger krekel
6ad16936bb bump version to 2.3.2, regen docs and changelog 2012-10-25 13:48:31 +02:00
holger krekel
bcb8dc71d2 fix issue208 and fix issue29 - avoid long pauses in traceback printing
by using the new getstatementrange() code of the py lib which uses
AST-parsing rather than the previous heuristic which had O(n^2) complexity
(with n = len(sourcelines))

- require new (in-dev) py version to
2012-10-25 12:08:11 +02:00
holger krekel
b8277bfed8 fix issue127 - improve pytest_addoption and related documentation 2012-10-25 11:07:07 +02:00
holger krekel
2637326782 improve support for trial a bit more: don't run trial's empty TestCase.runTest() method 2012-10-22 19:22:01 +02:00
holger krekel
aa79c0a4b9 fix unittest emulation: TestCase.runTest is now ignored
if there are test* methods.
2012-10-22 16:25:09 +02:00
holger krekel
05c86aeb28 make sure ihook uses a node's fspath - important for hooks
e.g. during a Module's collect to pick up conftest.py files
residing in the same dir
2012-10-22 16:12:22 +02:00
holger krekel
f28f073c7c fix teardown-ordering for parametrized setups/teardowns 2012-10-22 12:16:54 +02:00
holger krekel
036557ac18 fix issue206 - unset PYTHONDONTWRITEBYTECODE in assertrewrite test 2012-10-22 11:14:18 +02:00
holger krekel
1b61fbc8ed - fix test_nose.py by being more tolerant about the error message
(differs between py32 and py33, thanks Arfrever)
- use pypi again now that py is released
2012-10-22 10:55:59 +02:00
holger krekel
97f03edcd6 fix issue205 - nested conftest to pickup pycollect_makemodule - relates to the two
reports of a failing doc/en/example/py2py3.
2012-10-22 10:17:50 +02:00
holger krekel
7e5efa0005 mention twisted with external plugins 2012-10-22 09:32:41 +02:00
holger krekel
d55fc611c4 properly handle non-existent PYTHONPATH 2012-10-20 17:39:15 +02:00
holger krekel
720fe3405b allow to run self-tests with "python setup.py test" for pytest tests itself 2012-10-20 17:32:03 +02:00
holger krekel
c894b2b459 add tox.ini to distribution 2012-10-20 17:08:02 +02:00
holger krekel
6d5bf4b908 Added tag 2.3.1 for changeset acf0e1477fb1 2012-10-20 14:33:23 +02:00
holger krekel
d4d213f83d some more fixes 2012-10-20 14:10:12 +02:00
holger krekel
289ee1c6ea prepare a 2.3.1 2012-10-20 14:05:33 +02:00
holger krekel
f41f7fda68 improve --markers output 2012-10-20 13:56:53 +02:00
holger krekel
9ed127b5da fix issue203 - fixture functions with a scope=function should have a "self" that points to the actual instance with which the test functions run. 2012-10-20 09:59:20 +02:00
holger krekel
525b08bc5c some doc refinements 2012-10-20 09:52:03 +02:00
holger krekel
fae34ca5e3 proper version number (2.3.1.dev*) 2012-10-19 16:00:29 +02:00
holger krekel
0852e84d9f skip pexpect using tests on freebsd 2012-10-19 15:59:29 +02:00
holger krekel
76db624639 start new dev cycle 2012-10-19 15:01:29 +02:00
holger krekel
1e6ec9941c Added tag 2.3.0 for changeset c27a60097767 2012-10-19 15:01:15 +02:00
43 changed files with 580 additions and 444 deletions

View File

@@ -49,3 +49,5 @@ e5e1746a197f0398356a43fbe2eebac9690f795d 2.1.0
92b916483c1e65a80dc80e3f7816b39e84b36a4d 2.2.2
3c11c5c9776f3c678719161e96cc0a08169c1cb8 2.2.3
ad9fe504a371ad8eb613052d58f229aa66f53527 2.2.4
c27a60097767c16a54ae56d9669a77925b213b9b 2.3.0
acf0e1477fb19a1d35a4e40242b77fa6af32eb17 2.3.1

View File

@@ -1,10 +1,55 @@
Changes between 2.3.1 and 2.3.2
-----------------------------------
- fix issue208 and fix issue29 use new py version to avoid long pauses
when printing tracebacks in long modules
- fix issue205 - conftests in subdirs customizing
pytest_pycollect_makemodule and pytest_pycollect_makeitem
now work properly
- fix teardown-ordering for parametrized setups
- fix issue127 - better documentation for pytest_addoption
and related objects.
- fix unittest behaviour: TestCase.runtest only called if there are
test methods defined
- improve trial support: don't collect its empty
unittest.TestCase.runTest() method
- "python setup.py test" now works with pytest itself
- fix/improve internal/packaging related bits:
- exception message check of test_nose.py now passes on python33 as well
- issue206 - fix test_assertrewrite.py to work when a global
PYTHONDONTWRITEBYTECODE=1 is present
- add tox.ini to pytest distribution so that ignore-dirs and others config
bits are properly distributed for maintainers who run pytest-own tests
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 +59,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

View File

@@ -2,6 +2,7 @@ include CHANGELOG
include README.txt
include setup.py
include distribute_setup.py
include tox.ini
include LICENSE
graft doc
graft testing

View File

@@ -1,2 +1,2 @@
#
__version__ = '2.3.0'
__version__ = '2.3.2'

View File

@@ -19,7 +19,7 @@ def pytest_unconfigure(config):
fin()
class Parser:
""" Parser for command line arguments. """
""" Parser for command line arguments and ini-file values. """
def __init__(self, usage=None, processopt=None):
self._anonymous = OptionGroup("custom options", parser=self)
@@ -38,9 +38,14 @@ class Parser:
def getgroup(self, name, description="", after=None):
""" get (or create) a named option Group.
:name: unique name of the option group.
:name: name of the option group.
:description: long description for --help output.
:after: name of other group, used for ordering --help output.
The returned group object has an ``addoption`` method with the same
signature as :py:func:`parser.addoption
<_pytest.config.Parser.addoption>` but will be shown in the
respective group in the output of ``pytest. --help``.
"""
for group in self._groups:
if group.name == name:
@@ -54,7 +59,19 @@ class Parser:
return group
def addoption(self, *opts, **attrs):
""" add an optparse-style option. """
""" register a command line option.
:opts: option names, can be short or long options.
:attrs: same attributes which the ``add_option()`` function of the
`optparse library
<http://docs.python.org/library/optparse.html#module-optparse>`_
accepts.
After command line parsing options are available on the pytest config
object via ``config.option.NAME`` where ``NAME`` is usually set
by passing a ``dest`` attribute, for example
``addoption("--long", dest="NAME", ...)``.
"""
self._anonymous.addoption(*opts, **attrs)
def parse(self, args):
@@ -75,7 +92,15 @@ class Parser:
return args
def addini(self, name, help, type=None, default=None):
""" add an ini-file option with the given name and description. """
""" register an ini-file option.
:name: name of the ini-variable
:type: type of the variable, can be ``pathlist``, ``args`` or ``linelist``.
:default: default value if no ini-file option exists but is queried.
The value of ini-variables can be retrieved via a call to
:py:func:`config.getini(name) <_pytest.config.Config.getini>`.
"""
assert type in (None, "pathlist", "args", "linelist")
self._inidict[name] = (help, type, default)
self._ininames.append(name)
@@ -246,8 +271,9 @@ class CmdOptions(object):
class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """
def __init__(self, pluginmanager=None):
#: command line option values, usually added via parser.addoption(...)
#: or parser.getgroup(...).addoption(...) calls
#: command line option values, which must have been previously added
#: via calls like ``parser.addoption(...)`` or
#: ``parser.getgroup(groupname).addoption(...)``
self.option = CmdOptions()
self._parser = Parser(
usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",

View File

@@ -23,8 +23,10 @@ def pytest_cmdline_preparse(config, args):
"""modify command line arguments before option parsing. """
def pytest_addoption(parser):
"""add optparse-style options and ini-style config values via calls
to ``parser.addoption`` and ``parser.addini(...)``.
"""use the parser to add optparse-style options and ini-style
config values via calls, see :py:func:`parser.addoption(...)
<_pytest.config.Parser.addoption>`
and :py:func:`parser.addini(...) <_pytest.config.Parser.addini>`.
"""
def pytest_cmdline_main(config):

View File

@@ -211,14 +211,16 @@ class Node(object):
#: filesystem path where this node was collected from (can be None)
self.fspath = getattr(parent, 'fspath', None)
#: fspath sensitive hook proxy used to call pytest hooks
self.ihook = self.session.gethookproxy(self.fspath)
#: keywords/markers collected from all scopes
self.keywords = NodeKeywords(self)
#self.extrainit()
@property
def ihook(self):
""" fspath sensitive hook proxy used to call pytest hooks"""
return self.session.gethookproxy(self.fspath)
#def extrainit(self):
# """"extra initialization after Node is initialized. Implemented
# by some subclasses. """

View File

@@ -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

View File

@@ -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):
@@ -149,8 +161,8 @@ def pytest_collect_file(path, parent):
break
else:
return
return parent.ihook.pytest_pycollect_makemodule(
path=path, parent=parent)
ihook = parent.session.gethookproxy(path)
return ihook.pytest_pycollect_makemodule(path=path, parent=parent)
def pytest_pycollect_makemodule(path, parent):
return Module(path, parent)
@@ -276,6 +288,7 @@ class PyCollector(PyobjMixin, pytest.Collector):
return l
def makeitem(self, name, obj):
#assert self.ihook.fspath == self.fspath, self
return self.ihook.pytest_pycollect_makeitem(
collector=self, name=name, obj=obj)
@@ -1519,7 +1532,7 @@ class FixtureManager:
item.session._setupstate._callfinalizers((name, param))
l = self._arg2finish.get(name)
if l is not None:
for fin in l:
for fin in reversed(l):
fin()
def parsefactories(self, node_or_obj, nodeid=None, unittest=False):
@@ -1621,7 +1634,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

View File

@@ -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():

View File

@@ -28,6 +28,7 @@ class UnitTestCase(pytest.Class):
loader = py.std.unittest.TestLoader()
module = self.getparent(pytest.Module).obj
cls = self.obj
foundsomething = False
for name in loader.getTestCaseNames(self.obj):
x = getattr(self.obj, name)
funcobj = getattr(x, 'im_func', x)
@@ -35,9 +36,14 @@ class UnitTestCase(pytest.Class):
if hasattr(funcobj, 'todo'):
pytest.mark.xfail(reason=str(funcobj.todo))(funcobj)
yield TestCaseFunction(name, parent=self)
foundsomething = True
if getattr(self.obj, 'runTest', None) is not None:
yield TestCaseFunction('runTest', parent=self)
if not foundsomething:
runtest = getattr(self.obj, 'runTest', None)
if runtest is not None:
ut = sys.modules.get("twisted.trial.unittest", None)
if ut is None or runtest != ut.TestCase.runTest:
yield TestCaseFunction('runTest', parent=self)
def setup(self):
meth = getattr(self.obj, 'setUpClass', None)

View File

@@ -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"

View File

@@ -5,6 +5,8 @@ Release announcements
.. toctree::
:maxdepth: 2
release-2.3.2
release-2.3.1
release-2.3.0
release-2.2.4
release-2.2.2

View 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.

View File

@@ -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.2
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.2
collected 1 items
test_assert2.py F

View File

@@ -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.2
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 0x1439488>
==================== 1 failed, 1 passed in 0.01 seconds ====================
Accessing captured output from a test function

View File

@@ -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.4.2"
import sys, os
@@ -53,7 +53,7 @@ master_doc = 'contents'
# General information about the project.
project = u'pytest'
copyright = u'2011, holger krekel et alii'
copyright = u'2012, holger krekel'
@@ -197,7 +197,7 @@ htmlhelp_basename = 'pytestdoc'
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('contents', 'pytest.tex', u'pytest Documentation',
u'holger krekel et alii', 'manual'),
u'holger krekel, http://merlinux.eu', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -239,7 +239,7 @@ man_pages = [
epub_title = u'pytest'
epub_author = u'holger krekel at merlinux eu'
epub_publisher = u'holger krekel at merlinux eu'
epub_copyright = u'2011, holger krekel et alii'
epub_copyright = u'2012, holger krekel et alii'
# The language of the text. It defaults to the language option
# or en if the language is not set.

View File

@@ -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.2
collected 1 items
mymodule.py .

View File

@@ -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.

View 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

View File

@@ -26,25 +26,25 @@ 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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 2 items
test_server.py:3: test_send_http PASSED
=================== 1 tests deselected by "-m 'webtest'" ===================
================== 1 passed, 1 deselected in 0.00 seconds ==================
================== 1 passed, 1 deselected in 0.01 seconds ==================
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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 2 items
test_server.py:6: test_something_quick PASSED
================= 1 tests deselected by "-m 'not webtest'" =================
================== 1 passed, 1 deselected in 0.00 seconds ==================
================== 1 passed, 1 deselected in 0.01 seconds ==================
Registering markers
-------------------------------------
@@ -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.2
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.2
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.2
collected 4 items
test_mark_classlevel.py ..
@@ -223,18 +223,18 @@ 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.2
collected 1 items
test_someenv.py s
======================== 1 skipped in 0.00 seconds =========================
======================== 1 skipped in 0.01 seconds =========================
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.2
collected 1 items
test_someenv.py .
@@ -246,13 +246,13 @@ 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.2
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-99/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.2
collected 4 items
test_plat.py .

View File

@@ -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.2
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.2 -- /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.2
collected 2 items
<YamlFile 'test_simple.yml'>
<YamlItem 'ok'>
<YamlItem 'hello'>
============================= in 0.03 seconds =============================
============================= in 0.02 seconds =============================

View File

@@ -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.2
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.2
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.2
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 0x216ccb0>
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 0x216e8c0>, a = 1, b = 2
def test_equals(self, a, b):
> assert a == b

View File

@@ -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.2
collected 2 items
<Module 'check_myapp.py'>
<Class 'CheckMyApp'>
@@ -51,7 +51,7 @@ then the test collection looks like this::
<Function 'check_simple'>
<Function 'check_complex'>
============================= in 0.00 seconds =============================
============================= in 0.01 seconds =============================
Interpreting cmdline arguments as Python packages
-----------------------------------------------------
@@ -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.2
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.2
collected 1 items
<Module 'pkg/module_py2.py'>
<Function 'test_only_on_python2'>

View File

@@ -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.2
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 0x11f1e50>
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 0x121a320>()
E + and 43 = <function g at 0x121a398>()
failure_demo.py:28: AssertionError
____________________ TestFailing.test_simple_multiline _____________________
self = <failure_demo.TestFailing object at 0x27277d0>
self = <failure_demo.TestFailing object at 0x118e8d0>
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 0x1186310>
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 0x121a668>()
failure_demo.py:38: AssertionError
_________________ TestSpecialisedExplanations.test_eq_text _________________
self = <failure_demo.TestSpecialisedExplanations object at 0x2727c10>
self = <failure_demo.TestSpecialisedExplanations object at 0x11f2d90>
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 0x11e6b50>
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 0x1351ad0>
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 0x118ee10>
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 0x11f5d50>
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 0x118bc50>
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 0x1186fd0>
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 0x11f1d10>
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 0x118b290>
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 0x1351d90>
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 0x11f5fd0>
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 0x118ba10>
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 0x1351c90>
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 0x11f10d0>
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 0x1351d50>
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 0x118b3d0>.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 0x11f5dd0>.b
E + where <failure_demo.Foo object at 0x11f5dd0> = <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 0x1186a10>
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 0x118eb50>.b
E + where <failure_demo.Foo object at 0x118eb50> = <class 'failure_demo.Foo'>()
E + and 2 = <failure_demo.Bar object at 0x118e090>.b
E + where <failure_demo.Bar object at 0x118e090> = <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 0x117fe60>
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:851>:1: ValueError
______________________ TestRaises.test_raises_doesnt _______________________
self = <failure_demo.TestRaises instance at 0x27413b0>
self = <failure_demo.TestRaises instance at 0x1204170>
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 0x1214710>
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 0x12055f0>
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 0x11edef0>
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 0x11e3fc8>
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 0x11e19e0>
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 0x11e1c68>
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 0x12048c0>
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 0x11e9560>
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 0x11f99b8>('456')
E + where <built-in method startswith of str object at 0x11f99b8> = '123'.startswith
failure_demo.py:188: AssertionError
__________________ TestMoreErrors.test_startswith_nested ___________________
self = <failure_demo.TestMoreErrors instance at 0x272a0e0>
self = <failure_demo.TestMoreErrors instance at 0x1196bd8>
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 0x11f99b8>('456')
E + where <built-in method startswith of str object at 0x11f99b8> = '123'.startswith
E + where '123' = <function f at 0x120e938>()
E + and '456' = <function g at 0x120e9b0>()
failure_demo.py:195: AssertionError
_____________________ TestMoreErrors.test_global_func ______________________
self = <failure_demo.TestMoreErrors instance at 0x273b7a0>
self = <failure_demo.TestMoreErrors instance at 0x12147e8>
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 0x11e2e60>
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 0x11e2e60>.x
failure_demo.py:202: AssertionError
_______________________ TestMoreErrors.test_compare ________________________
self = <failure_demo.TestMoreErrors instance at 0x2729560>
self = <failure_demo.TestMoreErrors instance at 0x1216170>
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 0x1205050>
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.21 seconds =========================

View File

@@ -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.2
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.2
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-104/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.2
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.2
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.2 -- /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.2
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.2
collected 3 items
test_some_are_slow.py ...
@@ -327,7 +327,7 @@ Now we can profile which test functions execute the slowest::
========================= slowest 3 test durations =========================
0.20s call test_some_are_slow.py::test_funcslow2
0.10s call test_some_are_slow.py::test_funcslow1
0.00s setup test_some_are_slow.py::test_funcfast
0.00s call test_some_are_slow.py::test_funcfast
========================= 3 passed in 0.31 seconds =========================
incremental testing - test steps
@@ -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.2
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 0x269efc8>
def test_modification(self):
> assert 0

View File

@@ -25,10 +25,13 @@ how does py.test relate to twisted's trial?
Since some time py.test has builtin support for supporting tests
written using trial. It does not itself start a reactor, however,
and does not handle Deferreds returned from a test. Someone using
these features might eventually write a dedicated ``pytest-twisted``
plugin which will surely see strong support from the pytest development
team.
and does not handle Deferreds returned from a test in pytest style.
If you are using trial's unittest.TestCase chances are that you can
just run your tests even if you return Deferreds. In addition,
there also is a dedicated `pytest-twisted
<http://pypi.python.org/pypi/pytest-twisted`` plugin which allows to
return deferreds from pytest-style tests, allowing to use
:ref:`fixtures` and other features.
how does py.test work with Django?
++++++++++++++++++++++++++++++++++++++++++++++

View File

@@ -26,14 +26,14 @@ 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
incrementally from classic to new style, if you prefer. You can also
start out from existing :ref:`unittest.TestCase style <unittest.TestCase>`
or :ref:`nose based <nosestyle>` projects.
In addition, pytest continues to support :ref:`xunitsetup`. You can mix
both styles, moving incrementally from classic to new style, as you
prefer. You can also start out from existing :ref:`unittest.TestCase
style <unittest.TestCase>` or :ref:`nose based <nosestyle>` projects.
.. _`funcargs`:
.. _`funcarg mechanism`:
@@ -47,7 +47,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 +66,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.2
collected 1 items
test_smtpsimple.py F
@@ -79,7 +79,7 @@ fixture function. Running the test looks like this::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP instance at 0x1eade18>
smtp = <smtplib.SMTP instance at 0x16c2a28>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
@@ -89,7 +89,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.16 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 +143,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 +189,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.2
collected 2 items
test_module.py FF
@@ -195,7 +197,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 0x23ccef0>
def test_ehlo(smtp):
response = smtp.ehlo()
@@ -207,7 +209,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 0x23ccef0>
def test_noop(smtp):
response = smtp.noop()
@@ -216,28 +218,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.17 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 +271,12 @@ using it has executed::
$ py.test -s -q --tb=no
FF
finalizing <smtplib.SMTP instance at 0x1a9d5a8>
finalizing <smtplib.SMTP instance at 0x2a6afc8>
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 +302,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 +321,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 +331,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 +342,7 @@ So let's just do another run::
================================= FAILURES =================================
__________________________ test_ehlo[merlinux.eu] __________________________
smtp = <smtplib.SMTP instance at 0x1eae680>
smtp = <smtplib.SMTP instance at 0x2191050>
def test_ehlo(smtp):
response = smtp.ehlo()
@@ -340,7 +354,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 0x2191050>
def test_noop(smtp):
response = smtp.noop()
@@ -351,7 +365,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 0x22299e0>
def test_ehlo(smtp):
response = smtp.ehlo()
@@ -362,7 +376,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 0x22299e0>
def test_noop(smtp):
response = smtp.noop()
@@ -410,21 +424,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.2 -- /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 5.45 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 +489,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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 8 items
test_module.py:16: test_0[1] PASSED

View File

@@ -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.2, 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.2
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 0x1e94c20>
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-917/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-917/test_needsfiles0
Before the test runs, a unique-per-test-invocation temporary directory
was created. More info at :ref:`tmpdir handling`.

View File

@@ -34,8 +34,9 @@ pytest: makes you write better programs
**integrates many common testing methods**:
- can run many ``nose``, ``unittest.py`` and ``doctest.py`` style
tests, including running testcases made for Django and trial
- multi-paradigm: pytest can run many ``nose``, ``unittest.py`` and
``doctest.py`` style test suites, including running testcases made for
Django and trial
- supports :ref:`good integration practises <goodpractises>`
- supports extended :ref:`xUnit style setup <xunitsetup>`
- supports domain-specific :ref:`non-python tests`

View File

@@ -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.2
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 0x2ada15bd2030>()
E + where <built-in method isalpha of str object at 0x2ada15bd2030> = '!'.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:960: got empty parameter set, function test_valid_string at /tmp/doc-exec-69/test_strings.py:1
For further examples, you might want to look at :ref:`more
parametrization examples <paramexamples>`.

View File

@@ -71,6 +71,10 @@ there is no need to activate it. Here is a initial list of known plugins:
* `pytest-django <http://pypi.python.org/pypi/pytest-django>`_: write tests
for `django`_ apps, using pytest integration.
* `pytest-twisted <http://pypi.python.org/pypi/pytest-twisted>`_: write tests
for `twisted <http://twistedmatrix.com>`_ apps, starting a reactor and
processing deferreds from test functions.
* `pytest-capturelog <http://pypi.python.org/pypi/pytest-capturelog>`_:
to capture and assert about messages from the logging module

View File

@@ -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.2
collected 6 items
xfail_demo.py xxxxxx
@@ -149,7 +149,7 @@ Running it with the report-on-xfail option gives this output::
XFAIL xfail_demo.py::test_hello6
reason: reason
======================== 6 xfailed in 0.03 seconds =========================
======================== 6 xfailed in 0.04 seconds =========================
.. _`evaluation of skipif/xfail conditions`:

View File

@@ -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.2
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-918/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`:

View File

@@ -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.2
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 0x1f76290>
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 0x1f76290>
test_unittest_db.py:12: AssertionError
========================= 2 failed in 0.02 seconds =========================

View File

@@ -5,13 +5,16 @@
classic xunit-style setup
========================================
.. note::
This section describes the classic way how you can implement setup and
teardown on a per-module/class/function basis. It remains fully
supported but it is recommended to rather use the more flexible,
more modular and more scalable :ref:`fixture functions
<fixture>` for implementing for fixing test state for your tests.
This section describes a classic and popular way how you can implement
fixtures (setup and teardown test state) on a per-module/class/function basis.
pytest started supporting these methods around 2005 and subsequently
nose and the standard library introduced them (under slightly different
names). While these setup/teardown methods are and will remain fully
supported you may also use pytest's more powerful :ref:`fixture mechanism
<fixture>` which leverages the concept of dependency injection, allowing
for a more modular and more scalable approach for managing test state,
especially for larger projects and for functional testing. It is safe
to mix both fixture mechanisms.
Module level setup/teardown
--------------------------------------

View File

@@ -1,10 +1,10 @@
import os, sys
try:
from setuptools import setup
from setuptools import setup, Command
except ImportError:
from distribute_setup import use_setuptools
use_setuptools()
from setuptools import setup
from setuptools import setup, Command
long_description = """
cross-project testing tool for Python.
@@ -24,15 +24,16 @@ def main():
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
version='2.3.0',
version='2.3.2',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
author='Holger Krekel, Benjamin Peterson, Ronny Pfannschmidt, Floris Bruynooghe and others',
author_email='holger at merlinux.eu',
entry_points= make_entry_points(),
cmdclass = {'test': PyTest},
# the following should be enabled for release
install_requires=['py>=1.4.10'],
install_requires=['py>=1.4.11'],
classifiers=['Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
@@ -69,5 +70,20 @@ def make_entry_points():
l = ["%s = %s" % (x, points[x]) for x in keys]
return {'console_scripts': l}
class PyTest(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import sys,subprocess
PPATH=[x for x in os.environ.get("PYTHONPATH", "").split(":") if x]
PPATH.insert(0, os.getcwd())
os.environ["PYTHONPATH"] = ":".join(PPATH)
errno = subprocess.call([sys.executable, 'pytest.py'])
raise SystemExit(errno)
if __name__ == '__main__':
main()

View File

@@ -354,18 +354,21 @@ def test_no_bytecode():
@pytest.mark.skipif('"__pypy__" in sys.modules')
def test_pyc_vs_pyo(self, testdir, monkeypatch):
testdir.makepyfile("""
import pytest
def test_optimized():
"hello"
assert test_optimized.__doc__ is None""")
import pytest
def test_optimized():
"hello"
assert test_optimized.__doc__ is None"""
)
p = py.path.local.make_numbered_dir(prefix="runpytest-", keep=None,
rootdir=testdir.tmpdir)
tmp = "--basetemp=%s" % p
monkeypatch.setenv("PYTHONOPTIMIZE", "2")
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
assert testdir.runpybin("py.test", tmp).ret == 0
tagged = "test_pyc_vs_pyo." + PYTEST_TAG
assert tagged + ".pyo" in os.listdir("__pycache__")
monkeypatch.undo()
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
assert testdir.runpybin("py.test", tmp).ret == 1
assert tagged + ".pyc" in os.listdir("__pycache__")

View File

@@ -85,7 +85,7 @@ def test_nose_setup_func_failure(testdir):
""")
result = testdir.runpytest(p, '-p', 'nose')
result.stdout.fnmatch_lines([
"*TypeError: <lambda>() takes exactly 1*0 given*"
"*TypeError: <lambda>()*"
])

View File

@@ -404,6 +404,43 @@ class TestConftestCustomization:
"*<MyModule*xyz*",
])
def test_customized_pymakemodule_issue205_subdir(self, testdir):
b = testdir.mkdir("a").mkdir("b")
b.join("conftest.py").write(py.code.Source("""
def pytest_pycollect_makemodule(__multicall__):
mod = __multicall__.execute()
mod.obj.hello = "world"
return mod
"""))
b.join("test_module.py").write(py.code.Source("""
def test_hello():
assert hello == "world"
"""))
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_customized_pymakeitem(self, testdir):
b = testdir.mkdir("a").mkdir("b")
b.join("conftest.py").write(py.code.Source("""
def pytest_pycollect_makeitem(__multicall__):
result = __multicall__.execute()
if result:
for func in result:
func._some123 = "world"
return result
"""))
b.join("test_module.py").write(py.code.Source("""
import pytest
@pytest.fixture()
def obj(request):
return request.node._some123
def test_hello(obj):
assert obj == "world"
"""))
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_pytest_pycollect_makeitem(self, testdir):
testdir.makeconftest("""
import pytest
@@ -2037,6 +2074,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")
@@ -2733,6 +2785,43 @@ class TestFixtureMarker:
reprec = testdir.inline_run("-v")
reprec.assertoutcome(passed=12+1)
def test_parametrized_fixture_teardown_order(self, testdir):
testdir.makepyfile("""
import pytest
@pytest.fixture(params=[1,2], scope="class")
def param1(request):
return request.param
l = []
class TestClass:
@classmethod
@pytest.fixture(scope="class", autouse=True)
def setup1(self, request, param1):
l.append(1)
request.addfinalizer(self.teardown1)
@classmethod
def teardown1(self):
assert l.pop() == 1
@pytest.fixture(scope="class", autouse=True)
def setup2(self, request, param1):
l.append(2)
request.addfinalizer(self.teardown2)
@classmethod
def teardown2(self):
assert l.pop() == 2
def test(self):
pass
def test_finish():
assert not l
""")
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines("""
*3 passed*
""")
assert "error" not in result.stdout.str()
def test_parametrize_separated_lifecycle(self, testdir):
testdir.makepyfile("""
import pytest

View File

@@ -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*",
])

View File

@@ -18,12 +18,21 @@ def test_runTest_method(testdir):
testpath=testdir.makepyfile("""
import unittest
pytest_plugins = "pytest_unittest"
class MyTestCase(unittest.TestCase):
class MyTestCaseWithRunTest(unittest.TestCase):
def runTest(self):
self.assertEquals('foo', 'foo')
class MyTestCaseWithoutRunTest(unittest.TestCase):
def runTest(self):
self.assertEquals('foo', 'foo')
def test_something(self):
pass
""")
reprec = testdir.inline_run(testpath)
assert reprec.matchreport('runTest').passed
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines("""
*MyTestCaseWithRunTest.runTest*
*MyTestCaseWithoutRunTest.test_something*
*2 passed*
""")
def test_isclasscheck_issue53(testdir):
testpath = testdir.makepyfile("""
@@ -268,7 +277,27 @@ def test_testfunction_skip_property(testdir):
class TestTrialUnittest:
def setup_class(cls):
pytest.importorskip("twisted.trial.unittest")
cls.ut = pytest.importorskip("twisted.trial.unittest")
def test_trial_testcase_runtest_not_collected(self, testdir):
testdir.makepyfile("""
from twisted.trial.unittest import TestCase
class TC(TestCase):
def test_hello(self):
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
testdir.makepyfile("""
from twisted.trial.unittest import TestCase
class TC(TestCase):
def runTest(self):
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_trial_exceptions_with_skips(self, testdir):
testdir.makepyfile("""
@@ -313,7 +342,7 @@ class TestTrialUnittest:
"*i2wanto*",
"*sys.version_info*",
"*skip_in_method*",
"*5 skipped*3 xfail*1 xpass*",
"*4 skipped*3 xfail*1 xpass*",
])
def test_trial_error(self, testdir):

19
tox.ini
View File

@@ -1,10 +1,10 @@
[tox]
distshare={homedir}/.tox/distshare
envlist=py26,py27,py31,py32,py33,py27-xdist,py25,trial
envlist=py26,py27,py27-nobyte,py31,py32,py33,py27-xdist,py25,trial
indexserver=
pypi = http://pypi.python.org/simple
testrun = http://pypi.testrun.org
default = http://pypi.testrun.org
#default = http://pypi.testrun.org
[testenv]
changedir=testing
@@ -16,7 +16,6 @@ deps=
[testenv:genscript]
changedir=.
commands= py.test --genscript=pytest1
deps=py>=1.4.0
[testenv:py27-xdist]
changedir=.
@@ -24,14 +23,23 @@ basepython=python2.7
deps=pytest-xdist
commands=
py.test -n3 -rfsxX \
--ignore .tox --junitxml={envlogdir}/junit-{envname}.xml testing
--junitxml={envlogdir}/junit-{envname}.xml testing
[testenv:py27-nobyte]
changedir=.
basepython=python2.7
deps=pytest-xdist
setenv=
PYTHONDONTWRITEBYTECODE=1
commands=
py.test -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml []
[testenv:trial]
changedir=.
basepython=python2.6
deps=:pypi:twisted
:pypi:pexpect
py>=1.4.5.dev1
commands=
py.test -rsxf testing/test_unittest.py \
--junitxml={envlogdir}/junit-{envname}.xml {posargs:testing/test_unittest.py}
@@ -74,6 +82,7 @@ deps=py>=1.4.0
[testenv:py33]
deps=py>=1.4.0
:pypi:nose
[testenv:jython]
changedir=testing