Compare commits

..

27 Commits
2.3.2 ... 2.3.3

Author SHA1 Message Date
holger krekel
d6f10d502c fix py31 compat, amend setup.py long description 2012-11-06 15:36:11 +01:00
holger krekel
65d6ebe7d1 bump to 2.3.3, add release announce 2012-11-06 14:41:10 +01:00
holger krekel
33cd414420 fix issue127 improve pytest_addoption docs, add new config.getoption(name) method for consistency. 2012-11-06 14:09:12 +01:00
holger krekel
dba2a8bc64 fix issue217 - to support @mock.patch with pytest funcarg-fixtures, also split out python integration tests into python/integration.py and fix nose/mark tests 2012-11-06 11:04:11 +01:00
holger krekel
f203401964 amend changelog entries 2012-11-06 09:27:58 +01:00
holger krekel
c64699bba6 fix issue219 - add trove classifiers for py24-py33 2012-11-06 09:14:41 +01:00
holger krekel
002c5072af addresses issue209 - avoid error messages from pip on python2.4 related to file, however, never be imported with this interpreter 2012-11-06 09:08:54 +01:00
Ronny Pfannschmidt
b3c8991b22 add a xfailing test for issue 199 2012-11-05 21:52:12 +01:00
Ronny Pfannschmidt
1a41c9c001 update changelog 2012-11-05 21:31:08 +01:00
Ronny Pfannschmidt
df444906d6 merge pull request 2012-11-05 21:18:50 +01:00
Ronny Pfannschmidt
04754f6748 test call_optional not calling non-callable functions 2012-11-05 21:17:58 +01:00
holger krekel
d5ad91c64f fix issue209 - depend on pylib dev version which again supports python2.4 2012-11-05 12:21:58 +01:00
holger krekel
7e831b66ec fix issue148 - recognize @unittest.skip on classes, avoid setup/teardown 2012-11-03 20:54:48 +01:00
holger krekel
ba9b27fcd3 fix issue215 - refactor test_python.py into multiple files:
- python/collect.py cotaining the core collection nodes
- python/fixture.py containing funcargs/fixture code
- python/metafunc.py generate_tests and metafunc usage
- python/raises.py the pytest.raises implementation
2012-11-02 16:04:57 +01:00
holger krekel
ca281b7c1b remove unused code 2012-11-02 16:04:56 +01:00
holger krekel
fb173a97a8 extended - fix issue214 - ignore attribute-access errors with objects in test modules that can blow up (for example flask's request object) 2012-10-31 17:00:55 +01:00
holger krekel
983b2d2475 merge 2012-10-31 17:01:24 +01:00
Ronny Pfannschmidt
e7e5ee805f fix issue 214 - gracefully handle proxy objects that look like fixtures 2012-10-31 17:00:43 +01:00
holger krekel
67f8dd0cf2 remove issue that doesn't make sense anymore 2012-10-28 17:40:30 +01:00
holger krekel
07cc48517d fix wrong reference in basic fixture example, thanks for reporting! (closes #212) 2012-10-28 14:54:49 +01:00
holger krekel
fce13c3e46 re-allow to parametrize with values that don't support __eq__ (closes issue213) 2012-10-28 14:52:43 +01:00
holger krekel
573599beb3 i think "helps you write better programs" fits better than "makes" 2012-10-28 11:25:53 +01:00
holger krekel
6ebf39e9a6 fix wrong document version on pytest.org (closes #210) 2012-10-28 10:13:37 +01:00
holger krekel
6b6080ae6c remove unused code 2012-10-28 10:12:36 +01:00
holger krekel
427cf6f66d add release announce 2012-10-25 14:13:43 +02:00
holger krekel
2fc8ee0839 Added tag 2.3.2 for changeset 8738b828dec5 2012-10-25 14:13:06 +02:00
ataumoefolau
40a55a640c nose.py: don't try to call setup if it's not callable 2012-10-12 14:39:17 +10:00
43 changed files with 2130 additions and 1889 deletions

View File

@@ -51,3 +51,4 @@ e5e1746a197f0398356a43fbe2eebac9690f795d 2.1.0
ad9fe504a371ad8eb613052d58f229aa66f53527 2.2.4
c27a60097767c16a54ae56d9669a77925b213b9b 2.3.0
acf0e1477fb19a1d35a4e40242b77fa6af32eb17 2.3.1
8738b828dec53937765db71951ef955cca4c51f6 2.3.2

View File

@@ -1,3 +1,35 @@
Changes between 2.3.2 and 2.3.3
-----------------------------------
- fix issue214 - parse modules that contain special objects like e. g.
flask's request object which blows up on getattr access if no request
is active. thanks Thomas Waldmann.
- fix issue213 - allow to parametrize with values like numpy arrays that
do not support an __eq__ operator
- fix issue215 - split test_python.org into multiple files
- fix issue148 - @unittest.skip on classes is now recognized and avoids
calling setUpClass/tearDownClass, thanks Pavel Repin
- fix issue209 - reintroduce python2.4 support by depending on newer
pylib which re-introduced statement-finding for pre-AST interpreters
- nose support: only call setup if its a callable, thanks Andrew
Taumoefolau
- fix issue219 - add py2.4-3.3 classifiers to TROVE list
- in tracebacks *,** arg values are now shown next to normal arguments
(thanks Manuel Jacob)
- fix issue217 - support mock.patch with pytest's fixtures - note that
you need either mock-1.0.1 or the python3.3 builtin unittest.mock.
- fix issue127 - improve documentation for pytest_addoption() and
add a ``config.getoption(name)`` helper function for consistency.
Changes between 2.3.1 and 2.3.2
-----------------------------------

View File

@@ -48,59 +48,6 @@ if the signature of a decorated function does not match. XXX is it
not sufficient to always allow non-matches?
unify item/request classes, generalize items
---------------------------------------------------------------
tags: 2.4 wish
in lieu of extended parametrization and the new way to specify resource
factories in terms of the parametrize decorator, consider unification
of the item and request class. This also is connected with allowing
funcargs in setup functions. Example of new item API:
item.getresource("db") # alias for request.getfuncargvalue
item.addfinalizer(...)
item.cached_setup(...)
item.applymarker(...)
test classes/modules could then use this api via::
def pytest_runtest_setup(item):
use item API ...
introduction of this new method needs to be _fully_ backward compatible -
and the documentation needs to change along to mention this new way of
doing things.
impl note: probably Request._fillfixtures would be called from the
python plugins own pytest_runtest_setup(item) and would call
item.getresource(X) for all X in the funcargs of a function.
XXX is it possible to even put the above item API to Nodes, i.e. also
to Directorty/module/file/class collectors? Problem is that current
funcarg factories presume they are called with a per-function (even
per-funcarg-per-function) scope. Could there be small tweaks to the new
API that lift this restriction?
consider::
def setup_class(cls, tmpdir):
# would get a per-class tmpdir because tmpdir parametrization
# would know that it is called with a class scope
#
#
#
this looks very difficult because those setup functions are also used
by nose etc. Rather consider introduction of a new setup hook:
def setup_test(self, item):
self.db = item.cached_setup(..., scope='class')
self.tmpdir = item.getresource("tmpdir")
this should be compatible to unittest/nose and provide much of what
"testresources" provide. XXX This would not allow full parametrization
such that test function could be run multiple times with different
values. See "parametrized attributes" issue.
allow parametrized attributes on classes
--------------------------------------------------

View File

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

View File

@@ -34,7 +34,7 @@ else:
PYTEST_TAG = "%s-%s%s-PYTEST" % (impl, ver[0], ver[1])
del ver, impl
PYC_EXT = ".py" + ("c" if __debug__ else "o")
PYC_EXT = ".py" + (__debug__ and "c" or "o")
PYC_TAIL = "." + PYTEST_TAG + PYC_EXT
REWRITE_NEWLINES = sys.version_info[:2] != (2, 7) and sys.version_info < (3, 2)

View File

@@ -271,9 +271,8 @@ class CmdOptions(object):
class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """
def __init__(self, pluginmanager=None):
#: command line option values, which must have been previously added
#: via calls like ``parser.addoption(...)`` or
#: ``parser.getgroup(groupname).addoption(...)``
#: access to command line option as attributes.
#: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
self.option = CmdOptions()
self._parser = Parser(
usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
@@ -285,6 +284,7 @@ class Config(object):
self._conftest = Conftest(onimport=self._onimportconftest)
self.hook = self.pluginmanager.hook
self._inicache = {}
self._opt2dest = {}
self._cleanup = []
@classmethod
@@ -305,6 +305,9 @@ class Config(object):
self.pluginmanager.consider_conftest(conftestmodule)
def _processopt(self, opt):
for name in opt._short_opts + opt._long_opts:
self._opt2dest[name] = opt.dest
if hasattr(opt, 'default') and opt.dest:
if not hasattr(self.option, opt.dest):
setattr(self.option, opt.dest, opt.default)
@@ -383,8 +386,9 @@ class Config(object):
x.append(line) # modifies the cached list inline
def getini(self, name):
""" return configuration value from an ini file. If the
specified name hasn't been registered through a prior ``parse.addini``
""" return configuration value from an :ref:`ini file <inifiles>`. If the
specified name hasn't been registered through a prior
:py:func:`parser.addini <pytest.config.Parser.addini>`
call (usually from a plugin), a ValueError is raised. """
try:
return self._inicache[name]
@@ -438,8 +442,22 @@ class Config(object):
self._checkconftest(name)
return self._conftest.rget(name, path)
def getoption(self, name):
""" return command line option value.
:arg name: name of the option. You may also specify
the literal ``--OPT`` option instead of the "dest" option name.
"""
name = self._opt2dest.get(name, name)
try:
return getattr(self.option, name)
except AttributeError:
raise ValueError("no option named %r" % (name,))
def getvalue(self, name, path=None):
""" return ``name`` value looked set from command line options.
""" return command line option value.
:arg name: name of the command line option
(deprecated) if we can't find the option also lookup
the name in a matching conftest file.
@@ -477,14 +495,3 @@ def getcfg(args, inibasenames):
return iniconfig['pytest']
return {}
def findupwards(current, basename):
current = py.path.local(current)
while 1:
p = current.join(basename)
if p.check():
return p
p = current.dirpath()
if p == current:
return
current = p

View File

@@ -23,10 +23,28 @@ def pytest_cmdline_preparse(config, args):
"""modify command line arguments before option parsing. """
def pytest_addoption(parser):
"""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>`.
"""register optparse-style options and ini-style config values.
This function must be implemented in a :ref:`plugin <pluginorder>` and is
called once at the beginning of a test run.
:arg parser: To add command line options, call
:py:func:`parser.addoption(...) <_pytest.config.Parser.addoption>`.
To add ini-file values call :py:func:`parser.addini(...)
<_pytest.config.Parser.addini>`.
Options can later be accessed through the
:py:class:`config <_pytest.config.Config>` object, respectively:
- :py:func:`config.getoption(name) <_pytest.config.Config.getoption>` to
retrieve the value of a command line option.
- :py:func:`config.getini(name) <_pytest.config.Config.getini>` to retrieve
a value read from an ini-style file.
The config object is passed around on many internal objects via the ``.config``
attribute or can be retrieved as the ``pytestconfig`` fixture or accessed
via (deprecated) ``pytest.config``.
"""
def pytest_cmdline_main(config):
@@ -35,7 +53,7 @@ def pytest_cmdline_main(config):
pytest_cmdline_main.firstresult = True
def pytest_configure(config):
""" called after command line options have been parsed.
""" called after command line options have been parsed
and all plugins and initial conftest files been loaded.
"""

View File

@@ -41,7 +41,7 @@ def pytest_make_collect_report(collector):
def call_optional(obj, name):
method = getattr(obj, name, None)
if method is not None and not hasattr(method, "_pytestfixturefunction"):
if method is not None and not hasattr(method, "_pytestfixturefunction") and py.builtin.callable(method):
# If there's any problems allow the exception to raise rather than
# silently ignoring them
method()

View File

@@ -598,7 +598,7 @@ class CallSpec2(object):
if valtype == "funcargs":
self.params[arg] = id
self._arg2scopenum[arg] = scopenum
if val == _notexists:
if val is _notexists:
self._emptyparamspecified = True
self._idlist.append(id)
@@ -1286,12 +1286,6 @@ scopenum_subfunction = scopes.index("subfunction")
def scopemismatch(currentscope, newscope):
return scopes.index(newscope) > scopes.index(currentscope)
def slice_kwargs(names, kwargs):
new_kwargs = {}
for name in names:
new_kwargs[name] = kwargs[name]
return new_kwargs
class FixtureLookupError(LookupError):
""" could not return a requested Fixture (missing or invalid). """
def __init__(self, argname, request, msg=None):
@@ -1551,7 +1545,15 @@ class FixtureManager:
continue
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
# or are "@pytest.fixture" marked
marker = getattr(obj, "_pytestfixturefunction", None)
try:
marker = obj._pytestfixturefunction
except KeyboardInterrupt:
raise
except Exception:
# some objects raise errors like request (from flask import request)
# we don't expect them to be fixture functions
marker = None
if marker is None:
if not name.startswith(self._argprefix):
continue
@@ -1657,8 +1659,14 @@ class FixtureDef:
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
#assert not inspect.isclass(function)
realfunction = function
while hasattr(realfunction, "__wrapped__"):
realfunction = realfunction.__wrapped__
if startindex is None:
startindex = inspect.ismethod(function) and 1 or 0
if realfunction != function:
startindex += len(getattr(function, "patchings", []))
function = realfunction
argnames = inspect.getargs(py.code.getrawcode(function))[0]
defaults = getattr(function, 'func_defaults',
getattr(function, '__defaults__', None)) or ()

View File

@@ -46,12 +46,16 @@ class UnitTestCase(pytest.Class):
yield TestCaseFunction('runTest', parent=self)
def setup(self):
if getattr(self.obj, '__unittest_skip__', False):
return
meth = getattr(self.obj, 'setUpClass', None)
if meth is not None:
meth()
super(UnitTestCase, self).setup()
def teardown(self):
if getattr(self.obj, '__unittest_skip__', False):
return
meth = getattr(self.obj, 'tearDownClass', None)
if meth is not None:
meth()

View File

@@ -5,6 +5,7 @@ Release announcements
.. toctree::
:maxdepth: 2
release-2.3.3
release-2.3.2
release-2.3.1
release-2.3.0

View File

@@ -0,0 +1,57 @@
pytest-2.3.2: some fixes and more traceback-printing speed
===========================================================================
pytest-2.3.2 is a another stabilization release:
- issue 205: fixes a regression with conftest detection
- issue 208/29: fixes traceback-printing speed in some bad cases
- fix teardown-ordering for parametrized setups
- fix unittest and trial compat behaviour with respect to runTest() methods
- issue 206 and others: some improvements to packaging
- fix issue127 and others: improve some docs
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.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

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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x1439488>
setting up <function test_func2 at 0x2d63d70>
==================== 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.4.2"
version = release = "2.3.3"
import sys, os

View File

@@ -12,6 +12,8 @@ configurations files by using the general help option::
This will display command line and configuration file settings
which were registered by installed plugins.
.. _inifiles:
How test configuration is read from configuration INI-files
-------------------------------------------------------------

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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 1 items
mymodule.py .

View File

@@ -26,19 +26,19 @@ 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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux2 -- Python 2.7.3 -- pytest-2.3.3 -- /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.01 seconds ==================
================== 1 passed, 1 deselected in 0.02 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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux2 -- Python 2.7.3 -- pytest-2.3.3 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 2 items
test_server.py:6: test_something_quick PASSED
@@ -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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 4 items
test_mark_classlevel.py ..
@@ -194,7 +194,7 @@ specifies via named environments::
import pytest
def pytest_addoption(parser):
parser.addoption("-E", dest="env", action="store", metavar="NAME",
parser.addoption("-E", action="store", metavar="NAME",
help="only run tests matching the environment NAME.")
def pytest_configure(config):
@@ -206,7 +206,7 @@ specifies via named environments::
envmarker = item.keywords.get("env", None)
if envmarker is not None:
envname = envmarker.args[0]
if envname != item.config.option.env:
if envname != item.config.getoption("-E"):
pytest.skip("test requires env %r" % envname)
A test file using this local plugin::
@@ -223,7 +223,7 @@ the test needs::
$ py.test -E stage2
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 1 items
test_someenv.py s
@@ -234,7 +234,7 @@ 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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 1 items
test_someenv.py .
@@ -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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 4 items
test_plat.py s.s.
========================= short test summary info ==========================
SKIP [2] /tmp/doc-exec-99/conftest.py:12: cannot run on platform linux2
SKIP [2] /tmp/doc-exec-57/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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 2 items
test_simple.yml .F
@@ -37,7 +37,7 @@ now execute the test specification::
usecase execution failed
spec failed: 'some': 'other'
no further details known at this point.
==================== 1 failed, 1 passed in 0.03 seconds ====================
==================== 1 failed, 1 passed in 0.04 seconds ====================
You get one dot for the passing ``sub1: sub1`` check and one failure.
Obviously in the above ``conftest.py`` you'll want to implement a more
@@ -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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux2 -- Python 2.7.3 -- pytest-2.3.3 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 2 items
test_simple.yml:1: usecase: ok PASSED
@@ -67,17 +67,17 @@ consulted when reporting in ``verbose`` mode::
usecase execution failed
spec failed: 'some': 'other'
no further details known at this point.
==================== 1 failed, 1 passed in 0.03 seconds ====================
==================== 1 failed, 1 passed in 0.04 seconds ====================
While developing your custom test collection and execution it's also
interesting to just look at the collection tree::
nonpython $ py.test --collectonly
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 2 items
<YamlFile 'test_simple.yml'>
<YamlItem 'ok'>
<YamlItem 'hello'>
============================= in 0.02 seconds =============================
============================= in 0.04 seconds =============================

View File

@@ -2,10 +2,10 @@
import pytest
def pytest_collect_file(path, parent):
def pytest_collect_file(parent, path):
if path.ext == ".yml" and path.basename.startswith("test"):
return YamlFile(path, parent)
class YamlFile(pytest.File):
def collect(self):
import yaml # we need a yaml parser, e.g. PyYAML
@@ -17,7 +17,7 @@ class YamlItem(pytest.Item):
def __init__(self, name, parent, spec):
super(YamlItem, self).__init__(name, parent)
self.spec = spec
def runtest(self):
for name, value in self.spec.items():
# some custom test execution (dumb example follows)

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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x216ccb0>
db = <conftest.DB2 instance at 0x1d8aef0>
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 0x216e8c0>, a = 1, b = 2
self = <test_parametrize.TestClass instance at 0x1628cb0>, 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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 2 items
<Module 'check_myapp.py'>
<Class 'CheckMyApp'>
@@ -82,7 +82,7 @@ You can always peek at the collection tree without running tests like this::
. $ py.test --collectonly pythoncollection.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 3 items
<Module 'pythoncollection.py'>
<Function 'test_function'>
@@ -91,7 +91,7 @@ You can always peek at the collection tree without running tests like this::
<Function 'test_method'>
<Function 'test_anothermethod'>
============================= in 0.00 seconds =============================
============================= in 0.01 seconds =============================
customizing test collection to find all .py files
---------------------------------------------------------
@@ -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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x11f1e50>
self = <failure_demo.TestFailing object at 0x1136710>
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 0x121a320>()
E + and 43 = <function g at 0x121a398>()
E + where 42 = <function f at 0x1146410>()
E + and 43 = <function g at 0x1146488>()
failure_demo.py:28: AssertionError
____________________ TestFailing.test_simple_multiline _____________________
self = <failure_demo.TestFailing object at 0x118e8d0>
self = <failure_demo.TestFailing object at 0x11329d0>
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 0x1186310>
self = <failure_demo.TestFailing object at 0x10d09d0>
def test_not(self):
def f():
return 42
> assert not f()
E assert not 42
E + where 42 = <function f at 0x121a668>()
E + where 42 = <function f at 0x1146848>()
failure_demo.py:38: AssertionError
_________________ TestSpecialisedExplanations.test_eq_text _________________
self = <failure_demo.TestSpecialisedExplanations object at 0x11f2d90>
self = <failure_demo.TestSpecialisedExplanations object at 0x10ca210>
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 0x11e6b50>
self = <failure_demo.TestSpecialisedExplanations object at 0x11368d0>
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 0x1351ad0>
self = <failure_demo.TestSpecialisedExplanations object at 0x11340d0>
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 0x118ee10>
self = <failure_demo.TestSpecialisedExplanations object at 0x10cfd90>
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 0x11f5d50>
self = <failure_demo.TestSpecialisedExplanations object at 0x10d0b10>
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 0x118bc50>
self = <failure_demo.TestSpecialisedExplanations object at 0x1142dd0>
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 0x1186fd0>
self = <failure_demo.TestSpecialisedExplanations object at 0x1136850>
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 0x11f1d10>
self = <failure_demo.TestSpecialisedExplanations object at 0x1134e10>
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 0x118b290>
self = <failure_demo.TestSpecialisedExplanations object at 0x1169c90>
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 0x1351d90>
self = <failure_demo.TestSpecialisedExplanations object at 0x1142c50>
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 0x11f5fd0>
self = <failure_demo.TestSpecialisedExplanations object at 0x10d0d90>
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 0x118ba10>
self = <failure_demo.TestSpecialisedExplanations object at 0x10e0110>
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 0x1351c90>
self = <failure_demo.TestSpecialisedExplanations object at 0x10ca7d0>
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 0x11f10d0>
self = <failure_demo.TestSpecialisedExplanations object at 0x1142750>
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 0x1351d50>
self = <failure_demo.TestSpecialisedExplanations object at 0x1134410>
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 0x118b3d0>.b
E + where 1 = <failure_demo.Foo object at 0x10e07d0>.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 0x11f5dd0>.b
E + where <failure_demo.Foo object at 0x11f5dd0> = <class 'failure_demo.Foo'>()
E + where 1 = <failure_demo.Foo object at 0x1132390>.b
E + where <failure_demo.Foo object at 0x1132390> = <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 0x1186a10>
self = <failure_demo.Foo object at 0x1136fd0>
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 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'>()
E + where 1 = <failure_demo.Foo object at 0x1134c50>.b
E + where <failure_demo.Foo object at 0x1134c50> = <class 'failure_demo.Foo'>()
E + and 2 = <failure_demo.Bar object at 0x1134790>.b
E + where <failure_demo.Bar object at 0x1134790> = <class 'failure_demo.Bar'>()
failure_demo.py:124: AssertionError
__________________________ TestRaises.test_raises __________________________
self = <failure_demo.TestRaises instance at 0x117fe60>
self = <failure_demo.TestRaises instance at 0x10dc098>
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:851>:1: ValueError
<0-codegen /home/hpk/p/pytest/.tox/regen/lib/python2.7/site-packages/_pytest/python.py:851>:1: ValueError
______________________ TestRaises.test_raises_doesnt _______________________
self = <failure_demo.TestRaises instance at 0x1204170>
self = <failure_demo.TestRaises instance at 0x10d8320>
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 0x1214710>
self = <failure_demo.TestRaises instance at 0x10c0680>
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 0x12055f0>
self = <failure_demo.TestRaises instance at 0x11604d0>
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 0x11edef0>
self = <failure_demo.TestRaises instance at 0x10e2290>
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 0x11e3fc8>
self = <failure_demo.TestRaises instance at 0x10e2f80>
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 0x11e19e0>
self = <failure_demo.TestMoreErrors instance at 0x10d1b90>
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 0x11e1c68>
self = <failure_demo.TestMoreErrors instance at 0x114f3b0>
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 0x12048c0>
self = <failure_demo.TestMoreErrors instance at 0x11496c8>
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 0x11e9560>
self = <failure_demo.TestMoreErrors instance at 0x10cec20>
def test_startswith(self):
s = "123"
g = "456"
> assert s.startswith(g)
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 assert <built-in method startswith of str object at 0x113b918>('456')
E + where <built-in method startswith of str object at 0x113b918> = '123'.startswith
failure_demo.py:188: AssertionError
__________________ TestMoreErrors.test_startswith_nested ___________________
self = <failure_demo.TestMoreErrors instance at 0x1196bd8>
self = <failure_demo.TestMoreErrors instance at 0x10c87a0>
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 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>()
E assert <built-in method startswith of str object at 0x113b918>('456')
E + where <built-in method startswith of str object at 0x113b918> = '123'.startswith
E + where '123' = <function f at 0x10bea28>()
E + and '456' = <function g at 0x10beaa0>()
failure_demo.py:195: AssertionError
_____________________ TestMoreErrors.test_global_func ______________________
self = <failure_demo.TestMoreErrors instance at 0x12147e8>
self = <failure_demo.TestMoreErrors instance at 0x10c5488>
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 0x11e2e60>
self = <failure_demo.TestMoreErrors instance at 0x113f710>
def test_instance(self):
self.x = 6*7
> assert self.x != 42
E assert 42 != 42
E + where 42 = <failure_demo.TestMoreErrors instance at 0x11e2e60>.x
E + where 42 = <failure_demo.TestMoreErrors instance at 0x113f710>.x
failure_demo.py:202: AssertionError
_______________________ TestMoreErrors.test_compare ________________________
self = <failure_demo.TestMoreErrors instance at 0x1216170>
self = <failure_demo.TestMoreErrors instance at 0x10bae18>
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 0x1205050>
self = <failure_demo.TestMoreErrors instance at 0x1160248>
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.21 seconds =========================
======================== 39 failed in 0.25 seconds =========================

View File

@@ -33,7 +33,7 @@ provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`::
@pytest.fixture
def cmdopt(request):
return request.config.option.cmdopt
return request.config.getoption("--cmdopt")
Let's run this without supplying our new option::
@@ -106,7 +106,7 @@ directory with the above conftest.py::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 0 items
============================= in 0.00 seconds =============================
@@ -129,7 +129,7 @@ line option to control skipping of ``slow`` marked tests::
help="run slow tests")
def pytest_runtest_setup(item):
if 'slow' in item.keywords and not item.config.getvalue("runslow"):
if 'slow' in item.keywords and not item.config.getoption("--runslow"):
pytest.skip("need --runslow option to run")
We can now write a test module like this::
@@ -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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 2 items
test_module.py .s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-104/conftest.py:9: need --runslow option to run
SKIP [1] /tmp/doc-exec-62/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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux2 -- Python 2.7.3 -- pytest-2.3.3 -- /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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 3 items
test_some_are_slow.py ...
@@ -380,7 +380,7 @@ If we run this::
$ py.test -rx
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x269efc8>
self = <test_step.TestUserHandling instance at 0x2677b90>
def test_modification(self):
> assert 0
@@ -398,7 +398,7 @@ If we run this::
========================= short test summary info ==========================
XFAIL test_step.py::TestUserHandling::()::test_deletion
reason: previous test failed (test_modification)
============== 1 failed, 2 passed, 1 xfailed in 0.01 seconds ===============
============== 1 failed, 2 passed, 1 xfailed in 0.02 seconds ===============
We'll see that ``test_deletion`` was not executed because ``test_modification``
failed. It is reported as an "expected failure".

View File

@@ -65,13 +65,13 @@ using it::
assert "merlinux" in msg
assert 0 # for demo purposes
Here, the ``test_function`` needs the ``smtp`` fixture value. pytest
Here, the ``test_ehlo`` needs the ``smtp`` fixture value. pytest
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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 1 items
test_smtpsimple.py F
@@ -79,7 +79,7 @@ marked ``smtp`` fixture function. Running the test looks like this::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP instance at 0x16c2a28>
smtp = <smtplib.SMTP instance at 0x1992a70>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
@@ -89,7 +89,7 @@ marked ``smtp`` fixture function. Running the test looks like this::
E assert 0
test_smtpsimple.py:12: AssertionError
========================= 1 failed in 0.16 seconds =========================
========================= 1 failed in 0.30 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
@@ -189,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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
collected 2 items
test_module.py FF
@@ -197,7 +197,7 @@ inspect what is going on and can now run the tests::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP instance at 0x23ccef0>
smtp = <smtplib.SMTP instance at 0x2b8a248>
def test_ehlo(smtp):
response = smtp.ehlo()
@@ -209,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 0x23ccef0>
smtp = <smtplib.SMTP instance at 0x2b8a248>
def test_noop(smtp):
response = smtp.noop()
@@ -218,7 +218,7 @@ inspect what is going on and can now run the tests::
E assert 0
test_module.py:11: AssertionError
========================= 2 failed in 0.17 seconds =========================
========================= 2 failed in 0.48 seconds =========================
You see the two ``assert 0`` failing and more importantly you can also see
that the same (module-scoped) ``smtp`` object was passed into the two
@@ -271,7 +271,7 @@ using it has executed::
$ py.test -s -q --tb=no
FF
finalizing <smtplib.SMTP instance at 0x2a6afc8>
finalizing <smtplib.SMTP instance at 0x1584908>
We see that the ``smtp`` instance is finalized after the two
tests using it tests executed. If we had specified ``scope='function'``
@@ -342,7 +342,7 @@ So let's just do another run::
================================= FAILURES =================================
__________________________ test_ehlo[merlinux.eu] __________________________
smtp = <smtplib.SMTP instance at 0x2191050>
smtp = <smtplib.SMTP instance at 0x2368248>
def test_ehlo(smtp):
response = smtp.ehlo()
@@ -354,7 +354,7 @@ So let's just do another run::
test_module.py:6: AssertionError
__________________________ test_noop[merlinux.eu] __________________________
smtp = <smtplib.SMTP instance at 0x2191050>
smtp = <smtplib.SMTP instance at 0x2368248>
def test_noop(smtp):
response = smtp.noop()
@@ -365,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 0x22299e0>
smtp = <smtplib.SMTP instance at 0x2377680>
def test_ehlo(smtp):
response = smtp.ehlo()
@@ -376,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 0x22299e0>
smtp = <smtplib.SMTP instance at 0x2377680>
def test_noop(smtp):
response = smtp.noop()
@@ -424,13 +424,13 @@ 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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux2 -- Python 2.7.3 -- pytest-2.3.3 -- /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 5.45 seconds =========================
========================= 2 passed in 6.79 seconds =========================
Due to the parametrization of ``smtp`` the test will run twice with two
different ``App`` instances and respective smtp servers. There is no
@@ -489,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.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux2 -- Python 2.7.3 -- pytest-2.3.3 -- /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.2, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc
This is py.test version 2.3.3, imported from /home/hpk/p/pytest/.tox/regen/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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x1e94c20>
self = <test_class.TestClass instance at 0x22a4d40>
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-917/test_needsfiles0')
tmpdir = local('/tmp/pytest-594/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-917/test_needsfiles0
/tmp/pytest-594/test_needsfiles0
Before the test runs, a unique-per-test-invocation temporary directory
was created. More info at :ref:`tmpdir handling`.

View File

@@ -1,7 +1,7 @@
.. _features:
pytest: makes you write better programs
pytest: helps you write better programs
=============================================
**a mature full-featured Python testing tool**

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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x2ada15bd2030>()
E + where <built-in method isalpha of str object at 0x2ada15bd2030> = '!'.isalpha
E assert <built-in method isalpha of str object at 0x2b1792721fa8>()
E + where <built-in method isalpha of str object at 0x2b1792721fa8> = '!'.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:960: got empty parameter set, function test_valid_string at /tmp/doc-exec-69/test_strings.py:1
SKIP [1] /home/hpk/p/pytest/.tox/regen/lib/python2.7/site-packages/_pytest/python.py:960: got empty parameter set, function test_valid_string at /tmp/doc-exec-26/test_strings.py:1
For further examples, you might want to look at :ref:`more
parametrization examples <paramexamples>`.

View File

@@ -5,7 +5,7 @@ Working with plugins and conftest files
py.test implements all aspects of configuration, collection, running and reporting by calling `well specified hooks`_. Virtually any Python module can be registered as a plugin. It can implement any number of hook functions (usually two or three) which all have a ``pytest_`` prefix, making hook functions easy to distinguish and find. There are three basic location types:
* `builtin plugins`_: loaded from py.test's own ``pytest/plugin`` directory.
* `builtin plugins`_: loaded from py.test's internal ``_pytest`` directory.
* `external plugins`_: modules discovered through `setuptools entry points`_
* `conftest.py plugins`_: modules auto-discovered in test directories
@@ -155,6 +155,8 @@ If a package is installed this way, py.test will load
``myproject.pluginmodule`` as a plugin which can define
`well specified hooks`_.
.. _`pluginorder`:
Plugin discovery order at tool startup
--------------------------------------------
@@ -175,6 +177,7 @@ py.test loads plugin modules at tool startup in the following way:
* by recursively loading all plugins specified by the
``pytest_plugins`` variable in ``conftest.py`` files
Requiring/Loading plugins in a test module or conftest file
-------------------------------------------------------------

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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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.04 seconds =========================
======================== 6 xfailed in 0.05 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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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-918/test_create_file0')
tmpdir = local('/tmp/pytest-595/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.04 seconds =========================
========================= 1 failed in 0.03 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.2
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
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 0x1f76290>
E AssertionError: <conftest.DummyDB instance at 0x269e5a8>
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 0x1f76290>
E AssertionError: <conftest.DummyDB instance at 0x269e5a8>
test_unittest_db.py:12: AssertionError
========================= 2 failed in 0.02 seconds =========================

View File

@@ -7,15 +7,39 @@ except ImportError:
from setuptools import setup, Command
long_description = """
cross-project testing tool for Python.
The `py.test`` testing tool makes it easy to write small tests, yet
scales to support complex functional testing. It provides
Platforms: Linux, Win32, OSX
- `auto-discovery
<http://pytest.org/latest/goodpractises.html#python-test-discovery>`_
of test modules and functions,
- detailed info on failing `assert statements <http://pytest.org/latest/assert.html>`_ (no need to remember ``self.assert*`` names)
- `modular fixtures <http://pytest.org/latest/fixture.html>`_ for
managing small or parametrized long-lived test resources.
- multi-paradigm support: you can use ``py.test`` to run test suites based
on `unittest <http://pytest.org/latest/unittest.html>`_ (or trial),
`nose <http://pytest.org/latest/nose.html>`_
- single-source compatibility to Python2.4 all the way up to Python3.3,
PyPy and Jython.
Interpreters: Python versions 2.4 through to 3.3, Jython 2.5.1 and PyPy-1.9
- many `external plugins <http://pytest.org/latest/plugins.html#installing-external-plugins-searching>`_.
Bugs and issues: http://bitbucket.org/hpk42/pytest/issues/
A simple example for a test::
Web page: http://pytest.org
# content of test_module.py
def test_function():
i = 4
assert i == 3
which can be run with ``py.test test_module.py``. See `getting-started <http://pytest.org/latest/getting-started.html#our-first-test-run>`_ for more examples.
For much more info, including PDF docs, see
http://pytest.org
and report bugs at:
http://bitbucket.org/hpk42/pytest/issues/
(c) Holger Krekel and others, 2004-2012
"""
@@ -24,7 +48,7 @@ def main():
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
version='2.3.2',
version='2.3.3',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
@@ -33,7 +57,7 @@ def main():
entry_points= make_entry_points(),
cmdclass = {'test': PyTest},
# the following should be enabled for release
install_requires=['py>=1.4.11'],
install_requires=['py>=1.4.12'],
classifiers=['Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
@@ -43,8 +67,10 @@ def main():
'Topic :: Software Development :: Testing',
'Topic :: Software Development :: Libraries',
'Topic :: Utilities',
'Programming Language :: Python',
'Programming Language :: Python :: 3'],
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3'] + [
("Programming Language :: Python :: %s" % x) for x in
"2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split()],
packages=['_pytest', '_pytest.assertion'],
py_modules=['pytest'],
zip_safe=False,

721
testing/python/collect.py Normal file
View File

@@ -0,0 +1,721 @@
import pytest, py, sys
from _pytest import python as funcargs
from _pytest.python import FixtureLookupError
class TestModule:
def test_failing_import(self, testdir):
modcol = testdir.getmodulecol("import alksdjalskdjalkjals")
pytest.raises(ImportError, modcol.collect)
pytest.raises(ImportError, modcol.collect)
def test_import_duplicate(self, testdir):
a = testdir.mkdir("a")
b = testdir.mkdir("b")
p = a.ensure("test_whatever.py")
p.pyimport()
del py.std.sys.modules['test_whatever']
b.ensure("test_whatever.py")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*import*mismatch*",
"*imported*test_whatever*",
"*%s*" % a.join("test_whatever.py"),
"*not the same*",
"*%s*" % b.join("test_whatever.py"),
"*HINT*",
])
def test_syntax_error_in_module(self, testdir):
modcol = testdir.getmodulecol("this is a syntax error")
pytest.raises(modcol.CollectError, modcol.collect)
pytest.raises(modcol.CollectError, modcol.collect)
def test_module_considers_pluginmanager_at_import(self, testdir):
modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',")
pytest.raises(ImportError, "modcol.obj")
class TestClass:
def test_class_with_init_not_collected(self, testdir):
modcol = testdir.getmodulecol("""
class TestClass1:
def __init__(self):
pass
class TestClass2(object):
def __init__(self):
pass
""")
l = modcol.collect()
assert len(l) == 0
def test_class_subclassobject(self, testdir):
testdir.getmodulecol("""
class test(object):
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*collected 0*",
])
def test_setup_teardown_class_as_classmethod(self, testdir):
testdir.makepyfile(test_mod1="""
class TestClassMethod:
@classmethod
def setup_class(cls):
pass
def test_1(self):
pass
@classmethod
def teardown_class(cls):
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*1 passed*",
])
class TestGenerator:
def test_generative_functions(self, testdir):
modcol = testdir.getmodulecol("""
def func1(arg, arg2):
assert arg == arg2
def test_gen():
yield func1, 17, 3*5
yield func1, 42, 6*7
""")
colitems = modcol.collect()
assert len(colitems) == 1
gencol = colitems[0]
assert isinstance(gencol, pytest.Generator)
gencolitems = gencol.collect()
assert len(gencolitems) == 2
assert isinstance(gencolitems[0], pytest.Function)
assert isinstance(gencolitems[1], pytest.Function)
assert gencolitems[0].name == '[0]'
assert gencolitems[0].obj.__name__ == 'func1'
def test_generative_methods(self, testdir):
modcol = testdir.getmodulecol("""
def func1(arg, arg2):
assert arg == arg2
class TestGenMethods:
def test_gen(self):
yield func1, 17, 3*5
yield func1, 42, 6*7
""")
gencol = modcol.collect()[0].collect()[0].collect()[0]
assert isinstance(gencol, pytest.Generator)
gencolitems = gencol.collect()
assert len(gencolitems) == 2
assert isinstance(gencolitems[0], pytest.Function)
assert isinstance(gencolitems[1], pytest.Function)
assert gencolitems[0].name == '[0]'
assert gencolitems[0].obj.__name__ == 'func1'
def test_generative_functions_with_explicit_names(self, testdir):
modcol = testdir.getmodulecol("""
def func1(arg, arg2):
assert arg == arg2
def test_gen():
yield "seventeen", func1, 17, 3*5
yield "fortytwo", func1, 42, 6*7
""")
colitems = modcol.collect()
assert len(colitems) == 1
gencol = colitems[0]
assert isinstance(gencol, pytest.Generator)
gencolitems = gencol.collect()
assert len(gencolitems) == 2
assert isinstance(gencolitems[0], pytest.Function)
assert isinstance(gencolitems[1], pytest.Function)
assert gencolitems[0].name == "['seventeen']"
assert gencolitems[0].obj.__name__ == 'func1'
assert gencolitems[1].name == "['fortytwo']"
assert gencolitems[1].obj.__name__ == 'func1'
def test_generative_functions_unique_explicit_names(self, testdir):
# generative
modcol = testdir.getmodulecol("""
def func(): pass
def test_gen():
yield "name", func
yield "name", func
""")
colitems = modcol.collect()
assert len(colitems) == 1
gencol = colitems[0]
assert isinstance(gencol, pytest.Generator)
pytest.raises(ValueError, "gencol.collect()")
def test_generative_methods_with_explicit_names(self, testdir):
modcol = testdir.getmodulecol("""
def func1(arg, arg2):
assert arg == arg2
class TestGenMethods:
def test_gen(self):
yield "m1", func1, 17, 3*5
yield "m2", func1, 42, 6*7
""")
gencol = modcol.collect()[0].collect()[0].collect()[0]
assert isinstance(gencol, pytest.Generator)
gencolitems = gencol.collect()
assert len(gencolitems) == 2
assert isinstance(gencolitems[0], pytest.Function)
assert isinstance(gencolitems[1], pytest.Function)
assert gencolitems[0].name == "['m1']"
assert gencolitems[0].obj.__name__ == 'func1'
assert gencolitems[1].name == "['m2']"
assert gencolitems[1].obj.__name__ == 'func1'
def test_order_of_execution_generator_same_codeline(self, testdir, tmpdir):
o = testdir.makepyfile("""
def test_generative_order_of_execution():
import py, pytest
test_list = []
expected_list = list(range(6))
def list_append(item):
test_list.append(item)
def assert_order_of_execution():
py.builtin.print_('expected order', expected_list)
py.builtin.print_('but got ', test_list)
assert test_list == expected_list
for i in expected_list:
yield list_append, i
yield assert_order_of_execution
""")
reprec = testdir.inline_run(o)
passed, skipped, failed = reprec.countoutcomes()
assert passed == 7
assert not skipped and not failed
def test_order_of_execution_generator_different_codeline(self, testdir):
o = testdir.makepyfile("""
def test_generative_tests_different_codeline():
import py, pytest
test_list = []
expected_list = list(range(3))
def list_append_2():
test_list.append(2)
def list_append_1():
test_list.append(1)
def list_append_0():
test_list.append(0)
def assert_order_of_execution():
py.builtin.print_('expected order', expected_list)
py.builtin.print_('but got ', test_list)
assert test_list == expected_list
yield list_append_0
yield list_append_1
yield list_append_2
yield assert_order_of_execution
""")
reprec = testdir.inline_run(o)
passed, skipped, failed = reprec.countoutcomes()
assert passed == 4
assert not skipped and not failed
def test_setupstate_is_preserved_134(self, testdir):
# yield-based tests are messy wrt to setupstate because
# during collection they already invoke setup functions
# and then again when they are run. For now, we want to make sure
# that the old 1.3.4 behaviour is preserved such that all
# yielded functions all share the same "self" instance that
# has been used during collection.
o = testdir.makepyfile("""
setuplist = []
class TestClass:
def setup_method(self, func):
#print "setup_method", self, func
setuplist.append(self)
self.init = 42
def teardown_method(self, func):
self.init = None
def test_func1(self):
pass
def test_func2(self):
yield self.func2
yield self.func2
def func2(self):
assert self.init
def test_setuplist():
# once for test_func2 during collection
# once for test_func1 during test run
# once for test_func2 during test run
#print setuplist
assert len(setuplist) == 3, len(setuplist)
assert setuplist[0] == setuplist[2], setuplist
assert setuplist[1] != setuplist[2], setuplist
""")
reprec = testdir.inline_run(o, '-v')
passed, skipped, failed = reprec.countoutcomes()
assert passed == 4
assert not skipped and not failed
class TestFunction:
def test_getmodulecollector(self, testdir):
item = testdir.getitem("def test_func(): pass")
modcol = item.getparent(pytest.Module)
assert isinstance(modcol, pytest.Module)
assert hasattr(modcol.obj, 'test_func')
def test_function_equality(self, testdir, tmpdir):
from _pytest.python import FixtureManager
config = testdir.parseconfigure()
session = testdir.Session(config)
session._fixturemanager = FixtureManager(session)
def func1():
pass
def func2():
pass
f1 = pytest.Function(name="name", parent=session, config=config,
args=(1,), callobj=func1)
f2 = pytest.Function(name="name",config=config,
args=(1,), callobj=func2, parent=session)
assert not f1 == f2
assert f1 != f2
f3 = pytest.Function(name="name", parent=session, config=config,
args=(1,2), callobj=func2)
assert not f3 == f2
assert f3 != f2
assert not f3 == f1
assert f3 != f1
f1_b = pytest.Function(name="name", parent=session, config=config,
args=(1,), callobj=func1)
assert f1 == f1_b
assert not f1 != f1_b
def test_issue197_parametrize_emptyset(self, testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.parametrize('arg', [])
def test_function(arg):
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(skipped=1)
def test_issue213_parametrize_value_no_equal(self, testdir):
testdir.makepyfile("""
import pytest
class A:
def __eq__(self, other):
raise ValueError("not possible")
@pytest.mark.parametrize('arg', [A()])
def test_function(arg):
assert arg.__class__.__name__ == "A"
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_function_equality_with_callspec(self, testdir, tmpdir):
items = testdir.getitems("""
import pytest
@pytest.mark.parametrize('arg', [1,2])
def test_function(arg):
pass
""")
assert items[0] != items[1]
assert not (items[0] == items[1])
def test_pyfunc_call(self, testdir):
item = testdir.getitem("def test_func(): raise ValueError")
config = item.config
class MyPlugin1:
def pytest_pyfunc_call(self, pyfuncitem):
raise ValueError
class MyPlugin2:
def pytest_pyfunc_call(self, pyfuncitem):
return True
config.pluginmanager.register(MyPlugin1())
config.pluginmanager.register(MyPlugin2())
config.hook.pytest_pyfunc_call(pyfuncitem=item)
class TestSorting:
def test_check_equality(self, testdir):
modcol = testdir.getmodulecol("""
def test_pass(): pass
def test_fail(): assert 0
""")
fn1 = testdir.collect_by_name(modcol, "test_pass")
assert isinstance(fn1, pytest.Function)
fn2 = testdir.collect_by_name(modcol, "test_pass")
assert isinstance(fn2, pytest.Function)
assert fn1 == fn2
assert fn1 != modcol
if py.std.sys.version_info < (3, 0):
assert cmp(fn1, fn2) == 0
assert hash(fn1) == hash(fn2)
fn3 = testdir.collect_by_name(modcol, "test_fail")
assert isinstance(fn3, pytest.Function)
assert not (fn1 == fn3)
assert fn1 != fn3
for fn in fn1,fn2,fn3:
assert fn != 3
assert fn != modcol
assert fn != [1,2,3]
assert [1,2,3] != fn
assert modcol != fn
def test_allow_sane_sorting_for_decorators(self, testdir):
modcol = testdir.getmodulecol("""
def dec(f):
g = lambda: f(2)
g.place_as = f
return g
def test_b(y):
pass
test_b = dec(test_b)
def test_a(y):
pass
test_a = dec(test_a)
""")
colitems = modcol.collect()
assert len(colitems) == 2
assert [item.name for item in colitems] == ['test_b', 'test_a']
class TestConftestCustomization:
def test_pytest_pycollect_module(self, testdir):
testdir.makeconftest("""
import pytest
class MyModule(pytest.Module):
pass
def pytest_pycollect_makemodule(path, parent):
if path.basename == "test_xyz.py":
return MyModule(path, parent)
""")
testdir.makepyfile("def test_some(): pass")
testdir.makepyfile(test_xyz="def test_func(): pass")
result = testdir.runpytest("--collectonly")
result.stdout.fnmatch_lines([
"*<Module*test_pytest*",
"*<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
class MyFunction(pytest.Function):
pass
def pytest_pycollect_makeitem(collector, name, obj):
if name == "some":
return MyFunction(name, collector)
""")
testdir.makepyfile("def some(): pass")
result = testdir.runpytest("--collectonly")
result.stdout.fnmatch_lines([
"*MyFunction*some*",
])
def test_makeitem_non_underscore(self, testdir, monkeypatch):
modcol = testdir.getmodulecol("def _hello(): pass")
l = []
monkeypatch.setattr(pytest.Module, 'makeitem',
lambda self, name, obj: l.append(name))
l = modcol.collect()
assert '_hello' not in l
def test_setup_only_available_in_subdir(testdir):
sub1 = testdir.mkpydir("sub1")
sub2 = testdir.mkpydir("sub2")
sub1.join("conftest.py").write(py.code.Source("""
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub1"
def pytest_runtest_call(item):
assert item.fspath.purebasename == "test_in_sub1"
def pytest_runtest_teardown(item):
assert item.fspath.purebasename == "test_in_sub1"
"""))
sub2.join("conftest.py").write(py.code.Source("""
import pytest
def pytest_runtest_setup(item):
assert item.fspath.purebasename == "test_in_sub2"
def pytest_runtest_call(item):
assert item.fspath.purebasename == "test_in_sub2"
def pytest_runtest_teardown(item):
assert item.fspath.purebasename == "test_in_sub2"
"""))
sub1.join("test_in_sub1.py").write("def test_1(): pass")
sub2.join("test_in_sub2.py").write("def test_2(): pass")
result = testdir.runpytest("-v", "-s")
result.stdout.fnmatch_lines([
"*2 passed*"
])
def test_modulecol_roundtrip(testdir):
modcol = testdir.getmodulecol("pass", withinit=True)
trail = modcol.nodeid
newcol = modcol.session.perform_collect([trail], genitems=0)[0]
assert modcol.name == newcol.name
class TestTracebackCutting:
def test_skip_simple(self):
excinfo = pytest.raises(pytest.skip.Exception, 'pytest.skip("xxx")')
assert excinfo.traceback[-1].frame.code.name == "skip"
assert excinfo.traceback[-1].ishidden()
def test_traceback_argsetup(self, testdir):
testdir.makeconftest("""
def pytest_funcarg__hello(request):
raise ValueError("xyz")
""")
p = testdir.makepyfile("def test(hello): pass")
result = testdir.runpytest(p)
assert result.ret != 0
out = result.stdout.str()
assert out.find("xyz") != -1
assert out.find("conftest.py:2: ValueError") != -1
numentries = out.count("_ _ _") # separator for traceback entries
assert numentries == 0
result = testdir.runpytest("--fulltrace", p)
out = result.stdout.str()
assert out.find("conftest.py:2: ValueError") != -1
numentries = out.count("_ _ _ _") # separator for traceback entries
assert numentries > 3
def test_traceback_error_during_import(self, testdir):
testdir.makepyfile("""
x = 1
x = 2
x = 17
asd
""")
result = testdir.runpytest()
assert result.ret != 0
out = result.stdout.str()
assert "x = 1" not in out
assert "x = 2" not in out
result.stdout.fnmatch_lines([
">*asd*",
"E*NameError*",
])
result = testdir.runpytest("--fulltrace")
out = result.stdout.str()
assert "x = 1" in out
assert "x = 2" in out
result.stdout.fnmatch_lines([
">*asd*",
"E*NameError*",
])
class TestReportInfo:
def test_itemreport_reportinfo(self, testdir, linecomp):
testdir.makeconftest("""
import pytest
class MyFunction(pytest.Function):
def reportinfo(self):
return "ABCDE", 42, "custom"
def pytest_pycollect_makeitem(collector, name, obj):
if name == "test_func":
return MyFunction(name, parent=collector)
""")
item = testdir.getitem("def test_func(): pass")
runner = item.config.pluginmanager.getplugin("runner")
assert item.location == ("ABCDE", 42, "custom")
def test_func_reportinfo(self, testdir):
item = testdir.getitem("def test_func(): pass")
fspath, lineno, modpath = item.reportinfo()
assert fspath == item.fspath
assert lineno == 0
assert modpath == "test_func"
def test_class_reportinfo(self, testdir):
modcol = testdir.getmodulecol("""
# lineno 0
class TestClass:
def test_hello(self): pass
""")
classcol = testdir.collect_by_name(modcol, "TestClass")
fspath, lineno, msg = classcol.reportinfo()
assert fspath == modcol.fspath
assert lineno == 1
assert msg == "TestClass"
def test_generator_reportinfo(self, testdir):
modcol = testdir.getmodulecol("""
# lineno 0
def test_gen():
def check(x):
assert x
yield check, 3
""")
gencol = testdir.collect_by_name(modcol, "test_gen")
fspath, lineno, modpath = gencol.reportinfo()
assert fspath == modcol.fspath
assert lineno == 1
assert modpath == "test_gen"
genitem = gencol.collect()[0]
fspath, lineno, modpath = genitem.reportinfo()
assert fspath == modcol.fspath
assert lineno == 2
assert modpath == "test_gen[0]"
"""
def test_func():
pass
def test_genfunc():
def check(x):
pass
yield check, 3
class TestClass:
def test_method(self):
pass
"""
def test_customized_python_discovery(testdir):
testdir.makeini("""
[pytest]
python_files=check_*.py
python_classes=Check
python_functions=check
""")
p = testdir.makepyfile("""
def check_simple():
pass
class CheckMyApp:
def check_meth(self):
pass
""")
p2 = p.new(basename=p.basename.replace("test", "check"))
p.move(p2)
result = testdir.runpytest("--collectonly", "-s")
result.stdout.fnmatch_lines([
"*check_customized*",
"*check_simple*",
"*CheckMyApp*",
"*check_meth*",
])
result = testdir.runpytest()
assert result.ret == 0
result.stdout.fnmatch_lines([
"*2 passed*",
])
def test_collector_attributes(testdir):
testdir.makeconftest("""
import pytest
def pytest_pycollect_makeitem(collector):
assert collector.Function == pytest.Function
assert collector.Class == pytest.Class
assert collector.Instance == pytest.Instance
assert collector.Module == pytest.Module
""")
testdir.makepyfile("""
def test_hello():
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*1 passed*",
])
def test_customize_through_attributes(testdir):
testdir.makeconftest("""
import pytest
class MyFunction(pytest.Function):
pass
class MyInstance(pytest.Instance):
Function = MyFunction
class MyClass(pytest.Class):
Instance = MyInstance
def pytest_pycollect_makeitem(collector, name, obj):
if name.startswith("MyTestClass"):
return MyClass(name, parent=collector)
""")
testdir.makepyfile("""
class MyTestClass:
def test_hello(self):
pass
""")
result = testdir.runpytest("--collectonly")
result.stdout.fnmatch_lines([
"*MyClass*",
"*MyInstance*",
"*MyFunction*test_hello*",
])
def test_unorderable_types(testdir):
testdir.makepyfile("""
class TestJoinEmpty:
pass
def make_test():
class Test:
pass
Test.__name__ = "TestFoo"
return Test
TestFoo = make_test()
""")
result = testdir.runpytest()
assert "TypeError" not in result.stdout.str()
assert result.ret == 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
import pytest, py, sys
class TestOEJSKITSpecials:
def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage
testdir.makeconftest("""
import pytest
def pytest_pycollect_makeitem(collector, name, obj):
if name == "MyClass":
return MyCollector(name, parent=collector)
class MyCollector(pytest.Collector):
def reportinfo(self):
return self.fspath, 3, "xyz"
""")
modcol = testdir.getmodulecol("""
def pytest_funcarg__arg1(request):
return 42
class MyClass:
pass
""")
# this hook finds funcarg factories
rep = modcol.ihook.pytest_make_collect_report(collector=modcol)
clscol = rep.result[0]
clscol.obj = lambda arg1: None
clscol.funcargs = {}
pytest._fillfuncargs(clscol)
assert clscol.funcargs['arg1'] == 42
def test_autouse_fixture(self, testdir): # rough jstests usage
testdir.makeconftest("""
import pytest
def pytest_pycollect_makeitem(collector, name, obj):
if name == "MyClass":
return MyCollector(name, parent=collector)
class MyCollector(pytest.Collector):
def reportinfo(self):
return self.fspath, 3, "xyz"
""")
modcol = testdir.getmodulecol("""
import pytest
@pytest.fixture(autouse=True)
def hello():
pass
def pytest_funcarg__arg1(request):
return 42
class MyClass:
pass
""")
# this hook finds funcarg factories
rep = modcol.ihook.pytest_make_collect_report(collector=modcol)
clscol = rep.result[0]
clscol.obj = lambda: None
clscol.funcargs = {}
pytest._fillfuncargs(clscol)
assert not clscol.funcargs
class TestMockDecoration:
def test_wrapped_getfuncargnames(self):
from _pytest.python import getfuncargnames
def wrap(f):
def func():
pass
func.__wrapped__ = f
return func
@wrap
def f(x):
pass
l = getfuncargnames(f)
assert l == ("x",)
def test_wrapped_getfuncargnames_patching(self):
from _pytest.python import getfuncargnames
def wrap(f):
def func():
pass
func.__wrapped__ = f
func.patchings = ["qwe"]
return func
@wrap
def f(x, y, z):
pass
l = getfuncargnames(f)
assert l == ("y", "z")
def test_unittest_mock(self, testdir):
pytest.importorskip("unittest.mock")
testdir.makepyfile("""
import unittest.mock
class T(unittest.TestCase):
@unittest.mock.patch("os.path.abspath")
def test_hello(self, abspath):
import os
os.path.abspath("hello")
abspath.assert_any_call("hello")
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_mock(self, testdir):
pytest.importorskip("mock", "1.0.1")
testdir.makepyfile("""
import os
import unittest
import mock
class T(unittest.TestCase):
@mock.patch("os.path.abspath")
def test_hello(self, abspath):
os.path.abspath("hello")
abspath.assert_any_call("hello")
@mock.patch("os.path.abspath")
@mock.patch("os.path.normpath")
def test_someting(normpath, abspath, tmpdir):
abspath.return_value = "this"
os.path.normpath(os.path.abspath("hello"))
normpath.assert_any_call("this")
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2)

575
testing/python/metafunc.py Normal file
View File

@@ -0,0 +1,575 @@
import pytest, py, sys
from _pytest import python as funcargs
from _pytest.python import FixtureLookupError
class TestMetafunc:
def Metafunc(self, func):
# the unit tests of this class check if things work correctly
# on the funcarg level, so we don't need a full blown
# initiliazation
class FixtureInfo:
name2fixturedefs = None
def __init__(self, names):
self.names_closure = names
names = funcargs.getfuncargnames(func)
fixtureinfo = FixtureInfo(names)
return funcargs.Metafunc(func, fixtureinfo, None)
def test_no_funcargs(self, testdir):
def function(): pass
metafunc = self.Metafunc(function)
assert not metafunc.fixturenames
repr(metafunc._calls)
def test_function_basic(self):
def func(arg1, arg2="qwe"): pass
metafunc = self.Metafunc(func)
assert len(metafunc.fixturenames) == 1
assert 'arg1' in metafunc.fixturenames
assert metafunc.function is func
assert metafunc.cls is None
def test_addcall_no_args(self):
def func(arg1): pass
metafunc = self.Metafunc(func)
metafunc.addcall()
assert len(metafunc._calls) == 1
call = metafunc._calls[0]
assert call.id == "0"
assert not hasattr(call, 'param')
def test_addcall_id(self):
def func(arg1): pass
metafunc = self.Metafunc(func)
pytest.raises(ValueError, "metafunc.addcall(id=None)")
metafunc.addcall(id=1)
pytest.raises(ValueError, "metafunc.addcall(id=1)")
pytest.raises(ValueError, "metafunc.addcall(id='1')")
metafunc.addcall(id=2)
assert len(metafunc._calls) == 2
assert metafunc._calls[0].id == "1"
assert metafunc._calls[1].id == "2"
def test_addcall_param(self):
def func(arg1): pass
metafunc = self.Metafunc(func)
class obj: pass
metafunc.addcall(param=obj)
metafunc.addcall(param=obj)
metafunc.addcall(param=1)
assert len(metafunc._calls) == 3
assert metafunc._calls[0].getparam("arg1") == obj
assert metafunc._calls[1].getparam("arg1") == obj
assert metafunc._calls[2].getparam("arg1") == 1
def test_addcall_funcargs(self):
def func(x): pass
metafunc = self.Metafunc(func)
class obj: pass
metafunc.addcall(funcargs={"x": 2})
metafunc.addcall(funcargs={"x": 3})
pytest.raises(pytest.fail.Exception, "metafunc.addcall({'xyz': 0})")
assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == {'x': 2}
assert metafunc._calls[1].funcargs == {'x': 3}
assert not hasattr(metafunc._calls[1], 'param')
def test_parametrize_error(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.parametrize("x", [1,2])
pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5,6]))
pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5,6]))
metafunc.parametrize("y", [1,2])
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5,6]))
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5,6]))
def test_parametrize_and_id(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.parametrize("x", [1,2], ids=['basic', 'advanced'])
metafunc.parametrize("y", ["abc", "def"])
ids = [x.id for x in metafunc._calls]
assert ids == ["basic-abc", "basic-def", "advanced-abc", "advanced-def"]
def test_parametrize_with_userobjects(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
class A:
pass
metafunc.parametrize("x", [A(), A()])
metafunc.parametrize("y", list("ab"))
assert metafunc._calls[0].id == "x0-a"
assert metafunc._calls[1].id == "x0-b"
assert metafunc._calls[2].id == "x1-a"
assert metafunc._calls[3].id == "x1-b"
def test_idmaker_autoname(self):
from _pytest.python import idmaker
result = idmaker(("a", "b"), [("string", 1.0),
("st-ring", 2.0)])
assert result == ["string-1.0", "st-ring-2.0"]
result = idmaker(("a", "b"), [(object(), 1.0),
(object(), object())])
assert result == ["a0-1.0", "a1-b1"]
def test_addcall_and_parametrize(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.addcall({'x': 1})
metafunc.parametrize('y', [2,3])
assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == {'x': 1, 'y': 2}
assert metafunc._calls[1].funcargs == {'x': 1, 'y': 3}
assert metafunc._calls[0].id == "0-2"
assert metafunc._calls[1].id == "0-3"
def test_parametrize_indirect(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.parametrize('x', [1], indirect=True)
metafunc.parametrize('y', [2,3], indirect=True)
metafunc.parametrize('unnamed', [1], indirect=True)
assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == {}
assert metafunc._calls[1].funcargs == {}
assert metafunc._calls[0].params == dict(x=1,y=2, unnamed=1)
assert metafunc._calls[1].params == dict(x=1,y=3, unnamed=1)
def test_addcalls_and_parametrize_indirect(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.addcall(param="123")
metafunc.parametrize('x', [1], indirect=True)
metafunc.parametrize('y', [2,3], indirect=True)
assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == {}
assert metafunc._calls[1].funcargs == {}
assert metafunc._calls[0].params == dict(x=1,y=2)
assert metafunc._calls[1].params == dict(x=1,y=3)
def test_parametrize_functional(self, testdir):
testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.parametrize('x', [1,2], indirect=True)
metafunc.parametrize('y', [2])
def pytest_funcarg__x(request):
return request.param * 10
def pytest_funcarg__y(request):
return request.param
def test_simple(x,y):
assert x in (10,20)
assert y == 2
""")
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines([
"*test_simple*1-2*",
"*test_simple*2-2*",
"*2 passed*",
])
def test_parametrize_onearg(self):
metafunc = self.Metafunc(lambda x: None)
metafunc.parametrize("x", [1,2])
assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == dict(x=1)
assert metafunc._calls[0].id == "1"
assert metafunc._calls[1].funcargs == dict(x=2)
assert metafunc._calls[1].id == "2"
def test_parametrize_onearg_indirect(self):
metafunc = self.Metafunc(lambda x: None)
metafunc.parametrize("x", [1,2], indirect=True)
assert metafunc._calls[0].params == dict(x=1)
assert metafunc._calls[0].id == "1"
assert metafunc._calls[1].params == dict(x=2)
assert metafunc._calls[1].id == "2"
def test_parametrize_twoargs(self):
metafunc = self.Metafunc(lambda x,y: None)
metafunc.parametrize(("x", "y"), [(1,2), (3,4)])
assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == dict(x=1, y=2)
assert metafunc._calls[0].id == "1-2"
assert metafunc._calls[1].funcargs == dict(x=3, y=4)
assert metafunc._calls[1].id == "3-4"
def test_parametrize_multiple_times(self, testdir):
testdir.makepyfile("""
import pytest
pytestmark = pytest.mark.parametrize("x", [1,2])
def test_func(x):
assert 0, x
class TestClass:
pytestmark = pytest.mark.parametrize("y", [3,4])
def test_meth(self, x, y):
assert 0, x
""")
result = testdir.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines([
"*6 fail*",
])
def test_parametrize_class_scenarios(self, testdir):
testdir.makepyfile("""
# same as doc/en/example/parametrize scenario example
def pytest_generate_tests(metafunc):
idlist = []
argvalues = []
for scenario in metafunc.cls.scenarios:
idlist.append(scenario[0])
items = scenario[1].items()
argnames = [x[0] for x in items]
argvalues.append(([x[1] for x in items]))
metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class")
class Test(object):
scenarios = [['1', {'arg': {1: 2}, "arg2": "value2"}],
['2', {'arg':'value2', "arg2": "value2"}]]
def test_1(self, arg, arg2):
pass
def test_2(self, arg2, arg):
pass
def test_3(self, arg, arg2):
pass
""")
result = testdir.runpytest("-v")
assert result.ret == 0
result.stdout.fnmatch_lines("""
*test_1*1*
*test_2*1*
*test_3*1*
*test_1*2*
*test_2*2*
*test_3*2*
*6 passed*
""")
class TestMetafuncFunctional:
def test_attributes(self, testdir):
p = testdir.makepyfile("""
# assumes that generate/provide runs in the same process
import py, pytest
def pytest_generate_tests(metafunc):
metafunc.addcall(param=metafunc)
def pytest_funcarg__metafunc(request):
assert request._pyfuncitem._genid == "0"
return request.param
def test_function(metafunc, pytestconfig):
assert metafunc.config == pytestconfig
assert metafunc.module.__name__ == __name__
assert metafunc.function == test_function
assert metafunc.cls is None
class TestClass:
def test_method(self, metafunc, pytestconfig):
assert metafunc.config == pytestconfig
assert metafunc.module.__name__ == __name__
if py.std.sys.version_info > (3, 0):
unbound = TestClass.test_method
else:
unbound = TestClass.test_method.im_func
# XXX actually have an unbound test function here?
assert metafunc.function == unbound
assert metafunc.cls == TestClass
""")
result = testdir.runpytest(p, "-v")
result.stdout.fnmatch_lines([
"*2 passed in*",
])
def test_addcall_with_two_funcargs_generators(self, testdir):
testdir.makeconftest("""
def pytest_generate_tests(metafunc):
assert "arg1" in metafunc.fixturenames
metafunc.addcall(funcargs=dict(arg1=1, arg2=2))
""")
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.addcall(funcargs=dict(arg1=1, arg2=1))
class TestClass:
def test_myfunc(self, arg1, arg2):
assert arg1 == arg2
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_myfunc*0*PASS*",
"*test_myfunc*1*FAIL*",
"*1 failed, 1 passed*"
])
def test_two_functions(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.addcall(param=10)
metafunc.addcall(param=20)
def pytest_funcarg__arg1(request):
return request.param
def test_func1(arg1):
assert arg1 == 10
def test_func2(arg1):
assert arg1 in (10, 20)
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_func1*0*PASS*",
"*test_func1*1*FAIL*",
"*test_func2*PASS*",
"*1 failed, 3 passed*"
])
def test_noself_in_method(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
assert 'xyz' not in metafunc.fixturenames
class TestHello:
def test_hello(xyz):
pass
""")
result = testdir.runpytest(p)
result.stdout.fnmatch_lines([
"*1 pass*",
])
def test_generate_plugin_and_module(self, testdir):
testdir.makeconftest("""
def pytest_generate_tests(metafunc):
assert "arg1" in metafunc.fixturenames
metafunc.addcall(id="world", param=(2,100))
""")
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.addcall(param=(1,1), id="hello")
def pytest_funcarg__arg1(request):
return request.param[0]
def pytest_funcarg__arg2(request):
return request.param[1]
class TestClass:
def test_myfunc(self, arg1, arg2):
assert arg1 == arg2
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_myfunc*hello*PASS*",
"*test_myfunc*world*FAIL*",
"*1 failed, 1 passed*"
])
def test_generate_tests_in_class(self, testdir):
p = testdir.makepyfile("""
class TestClass:
def pytest_generate_tests(self, metafunc):
metafunc.addcall(funcargs={'hello': 'world'}, id="hello")
def test_myfunc(self, hello):
assert hello == "world"
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_myfunc*hello*PASS*",
"*1 passed*"
])
def test_two_functions_not_same_instance(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.addcall({'arg1': 10})
metafunc.addcall({'arg1': 20})
class TestClass:
def test_func(self, arg1):
assert not hasattr(self, 'x')
self.x = 1
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_func*0*PASS*",
"*test_func*1*PASS*",
"*2 pass*",
])
def test_issue28_setup_method_in_generate_tests(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.addcall({'arg1': 1})
class TestClass:
def test_method(self, arg1):
assert arg1 == self.val
def setup_method(self, func):
self.val = 1
""")
result = testdir.runpytest(p)
result.stdout.fnmatch_lines([
"*1 pass*",
])
def test_parametrize_functional2(self, testdir):
testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.parametrize("arg1", [1,2])
metafunc.parametrize("arg2", [4,5])
def test_hello(arg1, arg2):
assert 0, (arg1, arg2)
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*(1, 4)*",
"*(1, 5)*",
"*(2, 4)*",
"*(2, 5)*",
"*4 failed*",
])
def test_parametrize_and_inner_getfuncargvalue(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.parametrize("arg1", [1], indirect=True)
metafunc.parametrize("arg2", [10], indirect=True)
def pytest_funcarg__arg1(request):
x = request.getfuncargvalue("arg2")
return x + request.param
def pytest_funcarg__arg2(request):
return request.param
def test_func1(arg1, arg2):
assert arg1 == 11
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_func1*1*PASS*",
"*1 passed*"
])
def test_parametrize_on_setup_arg(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
assert "arg1" in metafunc.fixturenames
metafunc.parametrize("arg1", [1], indirect=True)
def pytest_funcarg__arg1(request):
return request.param
def pytest_funcarg__arg2(request, arg1):
return 10 * arg1
def test_func(arg2):
assert arg2 == 10
""")
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines([
"*test_func*1*PASS*",
"*1 passed*"
])
def test_parametrize_with_ids(self, testdir):
testdir.makepyfile("""
import pytest
def pytest_generate_tests(metafunc):
metafunc.parametrize(("a", "b"), [(1,1), (1,2)],
ids=["basic", "advanced"])
def test_function(a, b):
assert a == b
""")
result = testdir.runpytest("-v")
assert result.ret == 1
result.stdout.fnmatch_lines_random([
"*test_function*basic*PASSED",
"*test_function*advanced*FAILED",
])
def test_parametrize_without_ids(self, testdir):
testdir.makepyfile("""
import pytest
def pytest_generate_tests(metafunc):
metafunc.parametrize(("a", "b"),
[(1,object()), (1.3,object())])
def test_function(a, b):
assert 1
""")
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines("""
*test_function*1-b0*
*test_function*1.3-b1*
""")
@pytest.mark.parametrize(("scope", "length"),
[("module", 2), ("function", 4)])
def test_parametrize_scope_overrides(self, testdir, scope, length):
testdir.makepyfile("""
import pytest
l = []
def pytest_generate_tests(metafunc):
if "arg" in metafunc.funcargnames:
metafunc.parametrize("arg", [1,2], indirect=True,
scope=%r)
def pytest_funcarg__arg(request):
l.append(request.param)
return request.param
def test_hello(arg):
assert arg in (1,2)
def test_world(arg):
assert arg in (1,2)
def test_checklength():
assert len(l) == %d
""" % (scope, length))
reprec = testdir.inline_run()
reprec.assertoutcome(passed=5)
def test_usefixtures_seen_in_generate_tests(self, testdir):
testdir.makepyfile("""
import pytest
def pytest_generate_tests(metafunc):
assert "abc" in metafunc.fixturenames
metafunc.parametrize("abc", [1])
@pytest.mark.usefixtures("abc")
def test_function():
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_generate_tests_only_done_in_subdir(self, testdir):
sub1 = testdir.mkpydir("sub1")
sub2 = testdir.mkpydir("sub2")
sub1.join("conftest.py").write(py.code.Source("""
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_1"
"""))
sub2.join("conftest.py").write(py.code.Source("""
def pytest_generate_tests(metafunc):
assert metafunc.function.__name__ == "test_2"
"""))
sub1.join("test_in_sub1.py").write("def test_1(): pass")
sub2.join("test_in_sub2.py").write("def test_2(): pass")
result = testdir.runpytest("-v", "-s", sub1, sub2, sub1)
result.stdout.fnmatch_lines([
"*3 passed*"
])

64
testing/python/raises.py Normal file
View File

@@ -0,0 +1,64 @@
import pytest
class TestRaises:
def test_raises(self):
source = "int('qwe')"
excinfo = pytest.raises(ValueError, source)
code = excinfo.traceback[-1].frame.code
s = str(code.fullsource)
assert s == source
def test_raises_exec(self):
pytest.raises(ValueError, "a,x = []")
def test_raises_syntax_error(self):
pytest.raises(SyntaxError, "qwe qwe qwe")
def test_raises_function(self):
pytest.raises(ValueError, int, 'hello')
def test_raises_callable_no_exception(self):
class A:
def __call__(self):
pass
try:
pytest.raises(ValueError, A())
except pytest.raises.Exception:
pass
def test_raises_flip_builtin_AssertionError(self):
# we replace AssertionError on python level
# however c code might still raise the builtin one
from _pytest.assertion.util import BuiltinAssertionError
pytest.raises(AssertionError,"""
raise BuiltinAssertionError
""")
@pytest.mark.skipif('sys.version < "2.5"')
def test_raises_as_contextmanager(self, testdir):
testdir.makepyfile("""
from __future__ import with_statement
import py, pytest
def test_simple():
with pytest.raises(ZeroDivisionError) as excinfo:
assert isinstance(excinfo, py.code.ExceptionInfo)
1/0
print (excinfo)
assert excinfo.type == ZeroDivisionError
def test_noraise():
with pytest.raises(pytest.raises.Exception):
with pytest.raises(ValueError):
int()
def test_raise_wrong_exception_passes_by():
with pytest.raises(ZeroDivisionError):
with pytest.raises(ValueError):
1/0
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
'*3 passed*',
])

View File

@@ -103,6 +103,16 @@ class TestConfigAPI:
assert config.getvalue("x", o) == 1
pytest.raises(KeyError, 'config.getvalue("y", o)')
def test_config_getoption(self, testdir):
testdir.makeconftest("""
def pytest_addoption(parser):
parser.addoption("--hello", "-X", dest="hello")
""")
config = testdir.parseconfig("--hello=this")
for x in ("hello", "--hello", "-X"):
assert config.getoption(x) == "this"
pytest.raises(ValueError, "config.getoption('qweqwe')")
def test_config_getvalueorskip(self, testdir):
config = testdir.parseconfig()
pytest.raises(pytest.skip.Exception,
@@ -304,3 +314,4 @@ def test_cmdline_processargs_simple(testdir):
"*pytest*",
"*-h*",
])

View File

@@ -237,6 +237,25 @@ class TestFunctional:
assert l[1].args == ()
assert l[2].args == ("pos1", )
@pytest.mark.xfail(reason='unfixed')
def test_merging_markers_deep(self, testdir):
# issue 199 - propagate markers into nested classes
p = testdir.makepyfile("""
import pytest
class TestA:
pytestmark = pytest.mark.a
def test_b(self):
assert True
class TestC:
# this one didnt get marked
def test_d(self):
assert True
""")
items, rec = testdir.inline_genitems(p)
for item in items:
print (item, item.keywords)
assert 'a' in item.keywords
def test_mark_with_wrong_marker(self, testdir):
reprec = testdir.inline_runsource("""
import pytest

View File

@@ -35,6 +35,12 @@ def test_setup_func_with_setup_decorator():
assert not l
def test_setup_func_not_callable():
from _pytest.nose import call_optional
class A:
f = 1
call_optional(A(), "f")
def test_nose_setup_func(testdir):
p = testdir.makepyfile("""
from nose.tools import with_setup
@@ -97,21 +103,13 @@ def test_nose_setup_func_failure_2(testdir):
my_teardown = 2
def test_hello():
print (l)
assert l == [1]
def test_world():
print (l)
assert l == [1,2]
assert l == []
test_hello.setup = my_setup
test_hello.teardown = my_teardown
""")
result = testdir.runpytest(p, '-p', 'nose')
result.stdout.fnmatch_lines([
"*TypeError: 'int' object is not callable*"
])
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_nose_setup_partial(testdir):
py.test.importorskip("functools")

View File

@@ -96,6 +96,25 @@ def test_teardown(testdir):
assert passed == 2
assert passed + skipped + failed == 2
@pytest.mark.skipif("sys.version_info < (3,1)")
def test_unittest_skip_issue148(testdir):
testpath = testdir.makepyfile("""
import unittest
@unittest.skip("hello")
class MyTestCase(unittest.TestCase):
@classmethod
def setUpClass(self):
xxx
def test_one(self):
pass
@classmethod
def tearDownClass(self):
xxx
""")
reprec = testdir.inline_run(testpath)
reprec.assertoutcome(skipped=1)
def test_method_and_teardown_failing_reporting(testdir):
testdir.makepyfile("""
import unittest, pytest

View File

@@ -1,6 +1,6 @@
[tox]
distshare={homedir}/.tox/distshare
envlist=py26,py27,py27-nobyte,py31,py32,py33,py27-xdist,py25,trial
envlist=py24,py26,py27,py27-nobyte,py31,py32,py33,py27-xdist,py25,trial
indexserver=
pypi = http://pypi.python.org/simple
testrun = http://pypi.testrun.org
@@ -21,6 +21,8 @@ commands= py.test --genscript=pytest1
changedir=.
basepython=python2.7
deps=pytest-xdist
:pypi:mock
:pypi:nose
commands=
py.test -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml testing
@@ -96,7 +98,7 @@ plugins=pytester
#--pyargs --doctest-modules --ignore=.tox
addopts= -rxs
rsyncdirs=tox.ini pytest.py _pytest testing
python_files=test_*.py *_test.py
python_files=test_*.py *_test.py testing/*/*.py
python_classes=Test Acceptance
python_functions=test
pep8ignore = E401 E225 E261 E128 E124 E302