1

In my testing code, I have the following:

@pytest.mark.parametrize(("title", "description", 'site'), [
                        ("abc", "this is a proper description","minecraft.net"),
                        ("proper title","short","minecraft.net"),
                        ("proper title", "this is a proper description","bol"),
                        ("","this is a proper description","minecraft.net"),
                        ("proper title","","minecraft.net"),
                        ("proper title","this is a proper description",""),
                        ("proper title","this is a proper description","ftp://myftp.nl")
        ])
@ae_test(loggedin = True)
def test_mod_model_create_validation(title, description,site):
    ... testing code ....

So, the parameterize function tries to parameterize the function returned by my own @ae_test decorator, which looks like this:

def ae_test(prob=1.00,loggedin=False,is_admin=False):
    def create_wrapper(func):
        def run_test(*args,**kwargs):
            ... test setup code ...
            func(*args,**kwargs)
            ... test teardown code ...

this has worked for all my tests so far, but the parameterize function is complaining:

ValueError: <function run_test at 0x1029b55f0> has no argument 'title'

this error occurs in pytest/python.py on line 638

In response to the first comment, here's the complete stack trace:

==================================== ERRORS ====================================
___________________ ERROR collecting test_content_models.py ____________________
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/runner.py:120: in __init__
>               self.result = func()
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/main.py:304: in _memocollect
>       return self._memoizedcall('_collected', lambda: list(self.collect()))
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/main.py:228: in _memoizedcall
>           res = function()
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/main.py:304: in <lambda>
>   return self._memoizedcall('_collected', lambda: list(self.collect()))
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/python.py:207: in collect
>                   res = self.makeitem(name, obj)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/python.py:218: in makeitem
>           collector=self, name=name, obj=obj)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/main.py:141: in call_matching_hooks
>       return hookmethod.pcall(plugins, **kwargs)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/core.py:425: in pcall
>       return self._docall(methods, kwargs)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/core.py:432: in _docall
>           res = mc.execute()
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/core.py:350: in execute
>           res = method(**kwargs)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/python.py:103: in pytest_pycollect_makeitem
>               return collector._genfunctions(name, obj)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/python.py:232: in _genfunctions
>       gentesthook.pcall(plugins, metafunc=metafunc)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/core.py:425: in pcall
>       return self._docall(methods, kwargs)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/core.py:432: in _docall
>           res = mc.execute()
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/core.py:350: in execute
>           res = method(**kwargs)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/python.py:37: in pytest_generate_tests
>           metafunc.parametrize(*p.args, **p.kwargs)
/Library/Python/2.7/site-packages/pytest-2.2.4-py2.7.egg/_pytest/python.py:638: in parametrize
>                   raise ValueError("%r has no argument %r" %(self.function, arg))
E                   ValueError: <function run_test at 0x1029b55f0> has no argument 'title'
=========================== 1 error in 0.36 seconds ============================

but the problem really seams to come down to parameterize looking for an argument called 'title' and not finding it. That's because I'm using the **kw syntax. I'm expecting the parameterize function to just put a dict in there.

bigblind
  • 12,539
  • 14
  • 68
  • 123

1 Answers1

6

You're probably best off using the decorator.decorator decorator decorator to convert your ae_test decorator into a signature-preserving decorator:

from decorator import decorator

def ae_test(prob=1.00,loggedin=False,is_admin=False):
    @decorator
    def run_test(func, *args, **kwargs):
        ... test setup code ...
        func(*args,**kwargs)
        ... test teardown code ...
    return run_test
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • Can my `run_test` function keep the `(*arg, **kwargs)`, so it can be used on functions with different signatures? – bigblind Aug 30 '12 at 15:59
  • @sys.stderr absolutely, `decorator.decorator` will capture the return value of `create_wrapper` and restore its signature so it looks like `func`. – ecatmur Aug 30 '12 at 16:03
  • @acatmur Now, after decorating `create_wrapper`, I get this error: "ypeError: create_wrapper() takes exactly 1 argument (4 given)". This is because create_wrapper only takes the function. I have to use this three-nested-functions syntax to be able to pass parameters to my decorator. But, moving the decorator one function deeperr, to `run_test` which actually takes the 4 parameters, results in this error (I've included the line of code where it happens: `first = inspect.getargspec(caller)[0][0] # first arg \n E IndexError: list index out of range` – bigblind Aug 30 '12 at 16:17
  • @sys.stderr hmm, take a look at http://micheles.googlecode.com/hg/decorator/documentation.html#decorator-is-a-decorator – ecatmur Aug 30 '12 at 16:21
  • @sys.stderr ah, it expects a single function combining `func` and its arguments; see above. – ecatmur Aug 30 '12 at 16:23
  • 15
    +1 for saying "the `decorator.decorator` decorator decorator" :) – Andy Hayden Aug 30 '12 at 16:24