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
def getfuncargnames(function):
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
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',
getattr(function, '__defaults__', None)) or ()
numdefaults = len(defaults)
@ -518,7 +519,8 @@ class Metafunc:
self.config = config
self.module = module
self.function = function
self.funcargnames = getfuncargnames(function)
self.funcargnames = getfuncargnames(function,
startindex=int(cls is not None))
self.cls = cls
self.module = module
self._calls = []
@ -526,7 +528,11 @@ class Metafunc:
def addcall(self, funcargs=None, id=_notexists, param=_notexists):
""" 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
the test function.
@ -538,10 +544,13 @@ class Metafunc:
:arg param: will be exposed to a later funcarg factory invocation
through the ``request.param`` attribute. It allows to
defer test fixture setup activities to when an actual
test is run. Note that request.addcall() is called during
the collection phase of a test run.
test is run.
"""
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:
raise ValueError("id=None not allowed")
if id is _notexists:

View File

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

View File

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

View File

@ -915,11 +915,12 @@ class TestMetafunc:
assert metafunc._calls[2].param == 1
def test_addcall_funcargs(self):
def func(arg1): pass
def func(x): pass
metafunc = funcargs.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}
@ -1003,6 +1004,21 @@ class TestGenfuncFunctional:
"*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):
testdir.makeconftest("""
def pytest_generate_tests(metafunc):
@ -1339,5 +1355,3 @@ def test_customize_through_attributes(testdir):
"*MyInstance*",
"*MyFunction*test_hello*",
])