fix and improve error reporting for parametrizing funcargs (originally reported by antlong)

This commit is contained in:
holger krekel 2011-03-05 12:11:35 +01:00
parent fadd1a2313
commit 318e8a404b
4 changed files with 34 additions and 11 deletions

View File

@ -486,10 +486,11 @@ def hasinit(obj):
return True return True
def getfuncargnames(function): def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames # XXX merge with main.py's varnames
argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0] argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0]
startindex = py.std.inspect.ismethod(function) and 1 or 0 if startindex is None:
startindex = py.std.inspect.ismethod(function) and 1 or 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)
@ -518,7 +519,8 @@ class Metafunc:
self.config = config self.config = config
self.module = module self.module = module
self.function = function self.function = function
self.funcargnames = getfuncargnames(function) self.funcargnames = getfuncargnames(function,
startindex=int(cls is not None))
self.cls = cls self.cls = cls
self.module = module self.module = module
self._calls = [] self._calls = []
@ -526,7 +528,11 @@ class Metafunc:
def addcall(self, funcargs=None, id=_notexists, param=_notexists): def addcall(self, funcargs=None, id=_notexists, param=_notexists):
""" add a new call to the underlying test function during the """ add a new call to the underlying test function during the
collection phase of a test run. collection phase of a test run. Note that request.addcall() is
called during the test collection phase prior and independently
to actual test execution. Therefore you should perform setup
of resources in a funcarg factory which can be instrumented
with the ``param``.
:arg funcargs: argument keyword dictionary used when invoking :arg funcargs: argument keyword dictionary used when invoking
the test function. the test function.
@ -538,10 +544,13 @@ class Metafunc:
:arg param: will be exposed to a later funcarg factory invocation :arg param: will be exposed to a later funcarg factory invocation
through the ``request.param`` attribute. It allows to through the ``request.param`` attribute. It allows to
defer test fixture setup activities to when an actual defer test fixture setup activities to when an actual
test is run. Note that request.addcall() is called during test is run.
the collection phase of a test run.
""" """
assert funcargs is None or isinstance(funcargs, dict) assert funcargs is None or isinstance(funcargs, dict)
if funcargs is not None:
for name in funcargs:
if name not in self.funcargnames:
pytest.fail("funcarg %r not used in this function." % name)
if id is None: if id is None:
raise ValueError("id=None not allowed") raise ValueError("id=None not allowed")
if id is _notexists: if id is _notexists:

View File

@ -1,7 +1,7 @@
""" """
unit and functional testing with Python. unit and functional testing with Python.
""" """
__version__ = '2.0.2.dev2' __version__ = '2.0.2.dev3'
__all__ = ['main'] __all__ = ['main']
from _pytest.core import main, UsageError, _preloadplugins from _pytest.core import main, UsageError, _preloadplugins

View File

@ -22,7 +22,7 @@ def main():
name='pytest', name='pytest',
description='py.test: simple powerful testing with Python', description='py.test: simple powerful testing with Python',
long_description = long_description, long_description = long_description,
version='2.0.2.dev2', version='2.0.2.dev3',
url='http://pytest.org', url='http://pytest.org',
license='MIT license', license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

View File

@ -915,11 +915,12 @@ class TestMetafunc:
assert metafunc._calls[2].param == 1 assert metafunc._calls[2].param == 1
def test_addcall_funcargs(self): def test_addcall_funcargs(self):
def func(arg1): pass def func(x): pass
metafunc = funcargs.Metafunc(func) metafunc = funcargs.Metafunc(func)
class obj: pass class obj: pass
metafunc.addcall(funcargs={"x": 2}) metafunc.addcall(funcargs={"x": 2})
metafunc.addcall(funcargs={"x": 3}) metafunc.addcall(funcargs={"x": 3})
pytest.raises(pytest.fail.Exception, "metafunc.addcall({'xyz': 0})")
assert len(metafunc._calls) == 2 assert len(metafunc._calls) == 2
assert metafunc._calls[0].funcargs == {'x': 2} assert metafunc._calls[0].funcargs == {'x': 2}
assert metafunc._calls[1].funcargs == {'x': 3} assert metafunc._calls[1].funcargs == {'x': 3}
@ -1003,6 +1004,21 @@ class TestGenfuncFunctional:
"*1 failed, 3 passed*" "*1 failed, 3 passed*"
]) ])
def test_noself_in_method(self, testdir):
p = testdir.makepyfile("""
def pytest_generate_tests(metafunc):
assert 'xyz' not in metafunc.funcargnames
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): def test_generate_plugin_and_module(self, testdir):
testdir.makeconftest(""" testdir.makeconftest("""
def pytest_generate_tests(metafunc): def pytest_generate_tests(metafunc):
@ -1339,5 +1355,3 @@ def test_customize_through_attributes(testdir):
"*MyInstance*", "*MyInstance*",
"*MyFunction*test_hello*", "*MyFunction*test_hello*",
]) ])