Merge branch 'pytest-2.7'
This commit is contained in:
commit
6af7172204
24
.travis.yml
24
.travis.yml
|
@ -7,24 +7,26 @@ install: "pip install -U tox"
|
||||||
# # command to run tests
|
# # command to run tests
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
|
- TESTENV=coveralls
|
||||||
|
- TESTENV=doctesting
|
||||||
- TESTENV=flakes
|
- TESTENV=flakes
|
||||||
- TESTENV=py26
|
- TESTENV=py26
|
||||||
- TESTENV=py27
|
- TESTENV=py27
|
||||||
|
- TESTENV=py27-cxfreeze
|
||||||
|
- TESTENV=py27-nobyte
|
||||||
|
- TESTENV=py27-pexpect
|
||||||
|
- TESTENV=py27-subprocess
|
||||||
|
- TESTENV=py27-trial
|
||||||
|
- TESTENV=py27-xdist
|
||||||
|
- TESTENV=py33
|
||||||
- TESTENV=py33
|
- TESTENV=py33
|
||||||
- TESTENV=py34
|
- TESTENV=py34
|
||||||
|
- TESTENV=py34-pexpect
|
||||||
|
- TESTENV=py34-trial
|
||||||
|
- TESTENV=py34-trial
|
||||||
|
- TESTENV=py34-xdist
|
||||||
- TESTENV=py35
|
- TESTENV=py35
|
||||||
- TESTENV=pypy
|
- TESTENV=pypy
|
||||||
- TESTENV=py27-pexpect
|
|
||||||
- TESTENV=py34-pexpect
|
|
||||||
- TESTENV=py27-nobyte
|
|
||||||
- TESTENV=py27-xdist
|
|
||||||
- TESTENV=py34-xdist
|
|
||||||
- TESTENV=py27-trial
|
|
||||||
- TESTENV=py34-trial
|
|
||||||
- TESTENV=py27-subprocess
|
|
||||||
- TESTENV=doctesting
|
|
||||||
- TESTENV=py27-cxfreeze
|
|
||||||
- TESTENV=coveralls
|
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
# py35 is currently broken on travis, see #744
|
# py35 is currently broken on travis, see #744
|
||||||
|
|
1
AUTHORS
1
AUTHORS
|
@ -47,6 +47,7 @@ Marc Schlaich
|
||||||
Mark Abramowitz
|
Mark Abramowitz
|
||||||
Martijn Faassen
|
Martijn Faassen
|
||||||
Nicolas Delaby
|
Nicolas Delaby
|
||||||
|
Pieter Mulder
|
||||||
Piotr Banaszkiewicz
|
Piotr Banaszkiewicz
|
||||||
Punyashloka Biswal
|
Punyashloka Biswal
|
||||||
Ralf Schmitt
|
Ralf Schmitt
|
||||||
|
|
36
CHANGELOG
36
CHANGELOG
|
@ -1,10 +1,6 @@
|
||||||
2.8.0.dev (compared to 2.7.X)
|
2.8.0.dev (compared to 2.7.X)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
- fix issue744: fix for ast.Call changes in Python 3.5+. Thanks
|
|
||||||
Guido van Rossum, Matthias Bussonnier, Stefan Zimmermann and
|
|
||||||
Thomas Kluyver.
|
|
||||||
|
|
||||||
- fix issue768: docstrings found in python modules were not setting up session
|
- fix issue768: docstrings found in python modules were not setting up session
|
||||||
fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR.
|
fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
@ -27,7 +23,7 @@
|
||||||
|
|
||||||
- Summary bar now is colored yellow for warning
|
- Summary bar now is colored yellow for warning
|
||||||
situations such as: all tests either were skipped or xpass/xfailed,
|
situations such as: all tests either were skipped or xpass/xfailed,
|
||||||
or no tests were run at all (this is a partial fix for issue500).
|
or no tests were run at all (this is a partial fix for issue500).
|
||||||
Thanks Eric Siegerman.
|
Thanks Eric Siegerman.
|
||||||
|
|
||||||
- New `testdirs` ini option: list of directories to search for tests
|
- New `testdirs` ini option: list of directories to search for tests
|
||||||
|
@ -105,6 +101,34 @@
|
||||||
|
|
||||||
- add ``file`` and ``line`` attributes to JUnit-XML output.
|
- add ``file`` and ``line`` attributes to JUnit-XML output.
|
||||||
|
|
||||||
|
2.7.3 (compared to 2.7.2)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
- fix issue744: fix for ast.Call changes in Python 3.5+. Thanks
|
||||||
|
Guido van Rossum, Matthias Bussonnier, Stefan Zimmermann and
|
||||||
|
Thomas Kluyver.
|
||||||
|
|
||||||
|
- fix issue842: applying markers in classes no longer propagate this markers
|
||||||
|
to superclasses which also have markers.
|
||||||
|
Thanks xmo-odoo for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- preserve warning functions after call to pytest.deprecated_call. Thanks
|
||||||
|
Pieter Mulder for PR.
|
||||||
|
|
||||||
|
- fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the
|
||||||
|
fixtures declared on the first one.
|
||||||
|
Thanks Florian Bruhin for reporting and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix issue863: skipped tests now report the correct reason when a skip/xfail
|
||||||
|
condition is met when using multiple markers.
|
||||||
|
Thanks Raphael Pierzina for reporting and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- optimized tmpdir fixture initialization, which should make test sessions
|
||||||
|
faster (specially when using pytest-xdist). The only visible effect
|
||||||
|
is that now pytest uses a subdirectory in the $TEMP directory for all
|
||||||
|
directories created by this fixture (defaults to $TEMP/pytest-$USER).
|
||||||
|
Thanks Bruno Oliveira for the PR.
|
||||||
|
|
||||||
2.7.2 (compared to 2.7.1)
|
2.7.2 (compared to 2.7.1)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
@ -128,7 +152,7 @@
|
||||||
Thanks Thomas De Schampheleire for reporting and Bruno Oliveira for the PR.
|
Thanks Thomas De Schampheleire for reporting and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
- fix issue718: failed to create representation of sets containing unsortable
|
- fix issue718: failed to create representation of sets containing unsortable
|
||||||
elements in python 2. Thanks Edison Gustavo Muenz
|
elements in python 2. Thanks Edison Gustavo Muenz.
|
||||||
|
|
||||||
- fix issue756, fix issue752 (and similar issues): depend on py-1.4.29
|
- fix issue756, fix issue752 (and similar issues): depend on py-1.4.29
|
||||||
which has a refined algorithm for traceback generation.
|
which has a refined algorithm for traceback generation.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
""" generic mechanism for marking and selecting python functions. """
|
""" generic mechanism for marking and selecting python functions. """
|
||||||
|
import inspect
|
||||||
import py
|
import py
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,15 +254,17 @@ class MarkDecorator:
|
||||||
otherwise add *args/**kwargs in-place to mark information. """
|
otherwise add *args/**kwargs in-place to mark information. """
|
||||||
if args and not kwargs:
|
if args and not kwargs:
|
||||||
func = args[0]
|
func = args[0]
|
||||||
if len(args) == 1 and (istestfunc(func) or
|
is_class = inspect.isclass(func)
|
||||||
hasattr(func, '__bases__')):
|
if len(args) == 1 and (istestfunc(func) or is_class):
|
||||||
if hasattr(func, '__bases__'):
|
if is_class:
|
||||||
if hasattr(func, 'pytestmark'):
|
if hasattr(func, 'pytestmark'):
|
||||||
l = func.pytestmark
|
mark_list = func.pytestmark
|
||||||
if not isinstance(l, list):
|
if not isinstance(mark_list, list):
|
||||||
func.pytestmark = [l, self]
|
mark_list = [mark_list]
|
||||||
else:
|
# always work on a copy to avoid updating pytestmark
|
||||||
l.append(self)
|
# from a superclass by accident
|
||||||
|
mark_list = mark_list + [self]
|
||||||
|
func.pytestmark = mark_list
|
||||||
else:
|
else:
|
||||||
func.pytestmark = [self]
|
func.pytestmark = [self]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
""" Python test discovery, setup and run of test functions. """
|
""" Python test discovery, setup and run of test functions. """
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import functools
|
||||||
import py
|
import py
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
|
@ -22,15 +23,23 @@ callable = py.builtin.callable
|
||||||
# used to work around a python2 exception info leak
|
# used to work around a python2 exception info leak
|
||||||
exc_clear = getattr(sys, 'exc_clear', lambda: None)
|
exc_clear = getattr(sys, 'exc_clear', lambda: None)
|
||||||
|
|
||||||
|
|
||||||
def filter_traceback(entry):
|
def filter_traceback(entry):
|
||||||
return entry.path != cutdir1 and not entry.path.relto(cutdir2)
|
return entry.path != cutdir1 and not entry.path.relto(cutdir2)
|
||||||
|
|
||||||
|
|
||||||
def getfslineno(obj):
|
def get_real_func(obj):
|
||||||
# xxx let decorators etc specify a sane ordering
|
"""gets the real function object of the (possibly) wrapped object by
|
||||||
|
functools.wraps or functools.partial.
|
||||||
|
"""
|
||||||
while hasattr(obj, "__wrapped__"):
|
while hasattr(obj, "__wrapped__"):
|
||||||
obj = obj.__wrapped__
|
obj = obj.__wrapped__
|
||||||
|
if isinstance(obj, functools.partial):
|
||||||
|
obj = obj.func
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def getfslineno(obj):
|
||||||
|
# xxx let decorators etc specify a sane ordering
|
||||||
|
obj = get_real_func(obj)
|
||||||
if hasattr(obj, 'place_as'):
|
if hasattr(obj, 'place_as'):
|
||||||
obj = obj.place_as
|
obj = obj.place_as
|
||||||
fslineno = py.code.getfslineno(obj)
|
fslineno = py.code.getfslineno(obj)
|
||||||
|
@ -606,7 +615,7 @@ class FunctionMixin(PyobjMixin):
|
||||||
|
|
||||||
def _prunetraceback(self, excinfo):
|
def _prunetraceback(self, excinfo):
|
||||||
if hasattr(self, '_obj') and not self.config.option.fulltrace:
|
if hasattr(self, '_obj') and not self.config.option.fulltrace:
|
||||||
code = py.code.Code(self.obj)
|
code = py.code.Code(get_real_func(self.obj))
|
||||||
path, firstlineno = code.path, code.firstlineno
|
path, firstlineno = code.path, code.firstlineno
|
||||||
traceback = excinfo.traceback
|
traceback = excinfo.traceback
|
||||||
ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
|
ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
|
||||||
|
@ -976,21 +985,13 @@ def showfixtures(config):
|
||||||
def _showfixtures_main(config, session):
|
def _showfixtures_main(config, session):
|
||||||
session.perform_collect()
|
session.perform_collect()
|
||||||
curdir = py.path.local()
|
curdir = py.path.local()
|
||||||
if session.items:
|
|
||||||
nodeid = session.items[0].nodeid
|
|
||||||
else:
|
|
||||||
part = session._initialparts[0]
|
|
||||||
nodeid = "::".join(map(str, [curdir.bestrelpath(part[0])] + part[1:]))
|
|
||||||
nodeid.replace(session.fspath.sep, "/")
|
|
||||||
|
|
||||||
tw = py.io.TerminalWriter()
|
tw = py.io.TerminalWriter()
|
||||||
verbose = config.getvalue("verbose")
|
verbose = config.getvalue("verbose")
|
||||||
|
|
||||||
fm = session._fixturemanager
|
fm = session._fixturemanager
|
||||||
|
|
||||||
available = []
|
available = []
|
||||||
for argname in fm._arg2fixturedefs:
|
for argname, fixturedefs in fm._arg2fixturedefs.items():
|
||||||
fixturedefs = fm.getfixturedefs(argname, nodeid)
|
|
||||||
assert fixturedefs is not None
|
assert fixturedefs is not None
|
||||||
if not fixturedefs:
|
if not fixturedefs:
|
||||||
continue
|
continue
|
||||||
|
@ -1582,7 +1583,7 @@ class FixtureLookupError(LookupError):
|
||||||
for function in stack:
|
for function in stack:
|
||||||
fspath, lineno = getfslineno(function)
|
fspath, lineno = getfslineno(function)
|
||||||
try:
|
try:
|
||||||
lines, _ = inspect.getsourcelines(function)
|
lines, _ = inspect.getsourcelines(get_real_func(function))
|
||||||
except IOError:
|
except IOError:
|
||||||
error_msg = "file %s, line %s: source code not available"
|
error_msg = "file %s, line %s: source code not available"
|
||||||
addline(error_msg % (fspath, lineno+1))
|
addline(error_msg % (fspath, lineno+1))
|
||||||
|
@ -1970,7 +1971,15 @@ def getfuncargnames(function, startindex=None):
|
||||||
if realfunction != function:
|
if realfunction != function:
|
||||||
startindex += num_mock_patch_args(function)
|
startindex += num_mock_patch_args(function)
|
||||||
function = realfunction
|
function = realfunction
|
||||||
argnames = inspect.getargs(py.code.getrawcode(function))[0]
|
if isinstance(function, functools.partial):
|
||||||
|
argnames = inspect.getargs(py.code.getrawcode(function.func))[0]
|
||||||
|
partial = function
|
||||||
|
argnames = argnames[len(partial.args):]
|
||||||
|
if partial.keywords:
|
||||||
|
for kw in partial.keywords:
|
||||||
|
argnames.remove(kw)
|
||||||
|
else:
|
||||||
|
argnames = inspect.getargs(py.code.getrawcode(function))[0]
|
||||||
defaults = getattr(function, 'func_defaults',
|
defaults = getattr(function, 'func_defaults',
|
||||||
getattr(function, '__defaults__', None)) or ()
|
getattr(function, '__defaults__', None)) or ()
|
||||||
numdefaults = len(defaults)
|
numdefaults = len(defaults)
|
||||||
|
|
|
@ -45,8 +45,8 @@ def deprecated_call(func, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
ret = func(*args, **kwargs)
|
ret = func(*args, **kwargs)
|
||||||
finally:
|
finally:
|
||||||
warnings.warn_explicit = warn_explicit
|
warnings.warn_explicit = oldwarn_explicit
|
||||||
warnings.warn = warn
|
warnings.warn = oldwarn
|
||||||
if not l:
|
if not l:
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
raise AssertionError("%r did not produce DeprecationWarning" %(func,))
|
raise AssertionError("%r did not produce DeprecationWarning" %(func,))
|
||||||
|
|
|
@ -98,24 +98,36 @@ class MarkEvaluator:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _istrue(self):
|
def _istrue(self):
|
||||||
|
if hasattr(self, 'result'):
|
||||||
|
return self.result
|
||||||
if self.holder:
|
if self.holder:
|
||||||
d = self._getglobals()
|
d = self._getglobals()
|
||||||
if self.holder.args:
|
if self.holder.args:
|
||||||
self.result = False
|
self.result = False
|
||||||
for expr in self.holder.args:
|
# "holder" might be a MarkInfo or a MarkDecorator; only
|
||||||
self.expr = expr
|
# MarkInfo keeps track of all parameters it received in an
|
||||||
if isinstance(expr, py.builtin._basestring):
|
# _arglist attribute
|
||||||
result = cached_eval(self.item.config, expr, d)
|
if hasattr(self.holder, '_arglist'):
|
||||||
else:
|
arglist = self.holder._arglist
|
||||||
if self.get("reason") is None:
|
else:
|
||||||
# XXX better be checked at collection time
|
arglist = [(self.holder.args, self.holder.kwargs)]
|
||||||
pytest.fail("you need to specify reason=STRING "
|
for args, kwargs in arglist:
|
||||||
"when using booleans as conditions.")
|
for expr in args:
|
||||||
result = bool(expr)
|
|
||||||
if result:
|
|
||||||
self.result = True
|
|
||||||
self.expr = expr
|
self.expr = expr
|
||||||
break
|
if isinstance(expr, py.builtin._basestring):
|
||||||
|
result = cached_eval(self.item.config, expr, d)
|
||||||
|
else:
|
||||||
|
if "reason" not in kwargs:
|
||||||
|
# XXX better be checked at collection time
|
||||||
|
msg = "you need to specify reason=STRING " \
|
||||||
|
"when using booleans as conditions."
|
||||||
|
pytest.fail(msg)
|
||||||
|
result = bool(expr)
|
||||||
|
if result:
|
||||||
|
self.result = True
|
||||||
|
self.reason = kwargs.get('reason', None)
|
||||||
|
self.expr = expr
|
||||||
|
return self.result
|
||||||
else:
|
else:
|
||||||
self.result = True
|
self.result = True
|
||||||
return getattr(self, 'result', False)
|
return getattr(self, 'result', False)
|
||||||
|
@ -124,7 +136,7 @@ class MarkEvaluator:
|
||||||
return self.holder.kwargs.get(attr, default)
|
return self.holder.kwargs.get(attr, default)
|
||||||
|
|
||||||
def getexplanation(self):
|
def getexplanation(self):
|
||||||
expl = self.get('reason', None)
|
expl = getattr(self, 'reason', None) or self.get('reason', None)
|
||||||
if not expl:
|
if not expl:
|
||||||
if not hasattr(self, 'expr'):
|
if not hasattr(self, 'expr'):
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -52,7 +52,14 @@ class TempdirFactory:
|
||||||
basetemp.remove()
|
basetemp.remove()
|
||||||
basetemp.mkdir()
|
basetemp.mkdir()
|
||||||
else:
|
else:
|
||||||
basetemp = py.path.local.make_numbered_dir(prefix='pytest-')
|
# use a sub-directory in the temproot to speed-up
|
||||||
|
# make_numbered_dir() call
|
||||||
|
import getpass
|
||||||
|
temproot = py.path.local.get_temproot()
|
||||||
|
rootdir = temproot.join('pytest-%s' % getpass.getuser())
|
||||||
|
rootdir.ensure(dir=1)
|
||||||
|
basetemp = py.path.local.make_numbered_dir(prefix='pytest-',
|
||||||
|
rootdir=rootdir)
|
||||||
self._basetemp = t = basetemp.realpath()
|
self._basetemp = t = basetemp.realpath()
|
||||||
self.trace("new basetemp", t)
|
self.trace("new basetemp", t)
|
||||||
return t
|
return t
|
||||||
|
|
|
@ -106,15 +106,16 @@ Is using pytest fixtures versus xUnit setup a style question?
|
||||||
For simple applications and for people experienced with nose_ or
|
For simple applications and for people experienced with nose_ or
|
||||||
unittest-style test setup using `xUnit style setup`_ probably
|
unittest-style test setup using `xUnit style setup`_ probably
|
||||||
feels natural. For larger test suites, parametrized testing
|
feels natural. For larger test suites, parametrized testing
|
||||||
or setup of complex test resources using funcargs_ may feel more natural.
|
or setup of complex test resources using fixtures_ may feel more natural.
|
||||||
Moreover, funcargs are ideal for writing advanced test support
|
Moreover, fixtures are ideal for writing advanced test support
|
||||||
code (like e.g. the monkeypatch_, the tmpdir_ or capture_ funcargs)
|
code (like e.g. the monkeypatch_, the tmpdir_ or capture_ fixtures)
|
||||||
because the support code can register setup/teardown functions
|
because the support code can register setup/teardown functions
|
||||||
in a managed class/module/function scope.
|
in a managed class/module/function scope.
|
||||||
|
|
||||||
.. _monkeypatch: monkeypatch.html
|
.. _monkeypatch: monkeypatch.html
|
||||||
.. _tmpdir: tmpdir.html
|
.. _tmpdir: tmpdir.html
|
||||||
.. _capture: capture.html
|
.. _capture: capture.html
|
||||||
|
.. _fixtures: fixture.html
|
||||||
|
|
||||||
.. _`why pytest_pyfuncarg__ methods?`:
|
.. _`why pytest_pyfuncarg__ methods?`:
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
.. _`pytest_nose`: plugin/nose.html
|
.. _`pytest_nose`: plugin/nose.html
|
||||||
.. _`reStructured Text`: http://docutils.sourceforge.net
|
.. _`reStructured Text`: http://docutils.sourceforge.net
|
||||||
.. _`Python debugger`: http://docs.python.org/lib/module-pdb.html
|
.. _`Python debugger`: http://docs.python.org/lib/module-pdb.html
|
||||||
.. _nose: http://somethingaboutorange.com/mrl/projects/nose/
|
.. _nose: https://nose.readthedocs.org/en/latest/
|
||||||
.. _pytest: http://pypi.python.org/pypi/pytest
|
.. _pytest: http://pypi.python.org/pypi/pytest
|
||||||
.. _mercurial: http://mercurial.selenic.com/wiki/
|
.. _mercurial: http://mercurial.selenic.com/wiki/
|
||||||
.. _`setuptools`: http://pypi.python.org/pypi/setuptools
|
.. _`setuptools`: http://pypi.python.org/pypi/setuptools
|
||||||
|
|
|
@ -865,3 +865,47 @@ def test_unorderable_types(testdir):
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
assert "TypeError" not in result.stdout.str()
|
assert "TypeError" not in result.stdout.str()
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_functools_partial(testdir):
|
||||||
|
"""
|
||||||
|
Test that collection of functools.partial object works, and arguments
|
||||||
|
to the wrapped functions are dealt correctly (see #811).
|
||||||
|
"""
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import functools
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fix1():
|
||||||
|
return 'fix1'
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fix2():
|
||||||
|
return 'fix2'
|
||||||
|
|
||||||
|
def check1(i, fix1):
|
||||||
|
assert i == 2
|
||||||
|
assert fix1 == 'fix1'
|
||||||
|
|
||||||
|
def check2(fix1, i):
|
||||||
|
assert i == 2
|
||||||
|
assert fix1 == 'fix1'
|
||||||
|
|
||||||
|
def check3(fix1, i, fix2):
|
||||||
|
assert i == 2
|
||||||
|
assert fix1 == 'fix1'
|
||||||
|
assert fix2 == 'fix2'
|
||||||
|
|
||||||
|
test_ok_1 = functools.partial(check1, i=2)
|
||||||
|
test_ok_2 = functools.partial(check1, i=2, fix1='fix1')
|
||||||
|
test_ok_3 = functools.partial(check1, 2)
|
||||||
|
test_ok_4 = functools.partial(check2, i=2)
|
||||||
|
test_ok_5 = functools.partial(check3, i=2)
|
||||||
|
test_ok_6 = functools.partial(check3, i=2, fix1='fix1')
|
||||||
|
|
||||||
|
test_fail_1 = functools.partial(check2, 2)
|
||||||
|
test_fail_2 = functools.partial(check3, 2)
|
||||||
|
""")
|
||||||
|
result = testdir.inline_run()
|
||||||
|
result.assertoutcome(passed=6, failed=2)
|
||||||
|
|
|
@ -2482,6 +2482,44 @@ class TestShowFixtures:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def test_show_fixtures_different_files(self, testdir):
|
||||||
|
"""
|
||||||
|
#833: --fixtures only shows fixtures from first file
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(test_a='''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fix_a():
|
||||||
|
"""Fixture A"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_a(fix_a):
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
testdir.makepyfile(test_b='''
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fix_b():
|
||||||
|
"""Fixture B"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_b(fix_b):
|
||||||
|
pass
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest("--fixtures")
|
||||||
|
result.stdout.fnmatch_lines("""
|
||||||
|
* fixtures defined from test_a *
|
||||||
|
fix_a
|
||||||
|
Fixture A
|
||||||
|
|
||||||
|
* fixtures defined from test_b *
|
||||||
|
fix_b
|
||||||
|
Fixture B
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
class TestContextManagerFixtureFuncs:
|
class TestContextManagerFixtureFuncs:
|
||||||
def test_simple(self, testdir):
|
def test_simple(self, testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
|
|
|
@ -369,6 +369,45 @@ class TestFunctional:
|
||||||
print (item, item.keywords)
|
print (item, item.keywords)
|
||||||
assert 'a' in item.keywords
|
assert 'a' in item.keywords
|
||||||
|
|
||||||
|
def test_mark_decorator_subclass_does_not_propagate_to_base(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.a
|
||||||
|
class Base: pass
|
||||||
|
|
||||||
|
@pytest.mark.b
|
||||||
|
class Test1(Base):
|
||||||
|
def test_foo(self): pass
|
||||||
|
|
||||||
|
class Test2(Base):
|
||||||
|
def test_bar(self): pass
|
||||||
|
""")
|
||||||
|
items, rec = testdir.inline_genitems(p)
|
||||||
|
self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',))
|
||||||
|
|
||||||
|
def test_mark_decorator_baseclasses_merged(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.a
|
||||||
|
class Base: pass
|
||||||
|
|
||||||
|
@pytest.mark.b
|
||||||
|
class Base2(Base): pass
|
||||||
|
|
||||||
|
@pytest.mark.c
|
||||||
|
class Test1(Base2):
|
||||||
|
def test_foo(self): pass
|
||||||
|
|
||||||
|
class Test2(Base2):
|
||||||
|
@pytest.mark.d
|
||||||
|
def test_bar(self): pass
|
||||||
|
""")
|
||||||
|
items, rec = testdir.inline_genitems(p)
|
||||||
|
self.assert_markers(items, test_foo=('a', 'b', 'c'),
|
||||||
|
test_bar=('a', 'b', 'd'))
|
||||||
|
|
||||||
def test_mark_with_wrong_marker(self, testdir):
|
def test_mark_with_wrong_marker(self, testdir):
|
||||||
reprec = testdir.inline_runsource("""
|
reprec = testdir.inline_runsource("""
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -477,6 +516,22 @@ class TestFunctional:
|
||||||
reprec = testdir.inline_run("-m", "mark1")
|
reprec = testdir.inline_run("-m", "mark1")
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
|
def assert_markers(self, items, **expected):
|
||||||
|
"""assert that given items have expected marker names applied to them.
|
||||||
|
expected should be a dict of (item name -> seq of expected marker names)
|
||||||
|
|
||||||
|
.. note:: this could be moved to ``testdir`` if proven to be useful
|
||||||
|
to other modules.
|
||||||
|
"""
|
||||||
|
from _pytest.mark import MarkInfo
|
||||||
|
items = dict((x.name, x) for x in items)
|
||||||
|
for name, expected_markers in expected.items():
|
||||||
|
markers = items[name].keywords._markers
|
||||||
|
marker_names = set([name for (name, v) in markers.items()
|
||||||
|
if isinstance(v, MarkInfo)])
|
||||||
|
assert marker_names == set(expected_markers)
|
||||||
|
|
||||||
|
|
||||||
class TestKeywordSelection:
|
class TestKeywordSelection:
|
||||||
def test_select_simple(self, testdir):
|
def test_select_simple(self, testdir):
|
||||||
file_test = testdir.makepyfile("""
|
file_test = testdir.makepyfile("""
|
||||||
|
|
|
@ -63,12 +63,16 @@ def test_deprecated_call_ret():
|
||||||
assert ret == 42
|
assert ret == 42
|
||||||
|
|
||||||
def test_deprecated_call_preserves():
|
def test_deprecated_call_preserves():
|
||||||
r = py.std.warnings.onceregistry.copy()
|
onceregistry = py.std.warnings.onceregistry.copy()
|
||||||
f = py.std.warnings.filters[:]
|
filters = py.std.warnings.filters[:]
|
||||||
|
warn = py.std.warnings.warn
|
||||||
|
warn_explicit = py.std.warnings.warn_explicit
|
||||||
test_deprecated_call_raises()
|
test_deprecated_call_raises()
|
||||||
test_deprecated_call()
|
test_deprecated_call()
|
||||||
assert r == py.std.warnings.onceregistry
|
assert onceregistry == py.std.warnings.onceregistry
|
||||||
assert f == py.std.warnings.filters
|
assert filters == py.std.warnings.filters
|
||||||
|
assert warn is py.std.warnings.warn
|
||||||
|
assert warn_explicit is py.std.warnings.warn_explicit
|
||||||
|
|
||||||
def test_deprecated_explicit_call_raises():
|
def test_deprecated_explicit_call_raises():
|
||||||
pytest.raises(AssertionError,
|
pytest.raises(AssertionError,
|
||||||
|
|
|
@ -409,6 +409,26 @@ class TestSkipif:
|
||||||
])
|
])
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('marker, msg1, msg2', [
|
||||||
|
('skipif', 'SKIP', 'skipped'),
|
||||||
|
('xfail', 'XPASS', 'xpassed'),
|
||||||
|
])
|
||||||
|
def test_skipif_reporting_multiple(self, testdir, marker, msg1, msg2):
|
||||||
|
testdir.makepyfile(test_foo="""
|
||||||
|
import pytest
|
||||||
|
@pytest.mark.{marker}(False, reason='first_condition')
|
||||||
|
@pytest.mark.{marker}(True, reason='second_condition')
|
||||||
|
def test_foobar():
|
||||||
|
assert 1
|
||||||
|
""".format(marker=marker))
|
||||||
|
result = testdir.runpytest('-s', '-rsxX')
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
"*{msg1}*test_foo.py*second_condition*".format(msg1=msg1),
|
||||||
|
"*1 {msg2}*".format(msg2=msg2),
|
||||||
|
])
|
||||||
|
assert result.ret == 0
|
||||||
|
|
||||||
|
|
||||||
def test_skip_not_report_default(testdir):
|
def test_skip_not_report_default(testdir):
|
||||||
p = testdir.makepyfile(test_one="""
|
p = testdir.makepyfile(test_one="""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
4
tox.ini
4
tox.ini
|
@ -8,6 +8,7 @@ envlist=
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands= py.test --lsof -rfsxX {posargs:testing}
|
commands= py.test --lsof -rfsxX {posargs:testing}
|
||||||
|
passenv = USER USERNAME
|
||||||
deps=
|
deps=
|
||||||
nose
|
nose
|
||||||
mock
|
mock
|
||||||
|
@ -18,6 +19,7 @@ deps=
|
||||||
nose
|
nose
|
||||||
mock<1.1 # last supported version for py26
|
mock<1.1 # last supported version for py26
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
[testenv:py27-subprocess]
|
[testenv:py27-subprocess]
|
||||||
changedir=.
|
changedir=.
|
||||||
basepython=python2.7
|
basepython=python2.7
|
||||||
|
@ -27,6 +29,8 @@ deps=pytest-xdist
|
||||||
commands=
|
commands=
|
||||||
py.test -n3 -rfsxX --runpytest=subprocess {posargs:testing}
|
py.test -n3 -rfsxX --runpytest=subprocess {posargs:testing}
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> pytest-2.7
|
||||||
[testenv:genscript]
|
[testenv:genscript]
|
||||||
commands= py.test --genscript=pytest1
|
commands= py.test --genscript=pytest1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue