decorators don't play nice with nose?

Diez B. Roggisch deets at nospam.web.de
Mon Apr 6 23:11:08 CEST 2009


hyperboreean schrieb:
> Hi, I am trying to test the business part of a web service. For this I 
> am using unittest & nose.
> I wrote a decorator that should handle the xml test file retrieval, but 
> it seems I can't get it working with nose.
> Here's the code:
> 
> 
> * MyApp.py -- base test class *
> 
> import os
> import unittest
> 
> from MyApp.Core import XmlParser
> 
> 
> __all__ = ['MyAppTest', 'setup']
> 
> 
> PATH = os.path.dirname(__file__) or ''
> 
> 
> class setup(object):
>    """Decorator to ease the use of xml files in MyApp tests.
> 
>    The way it works it that it decorates a test method which has a first
>    default parameter called 'parser' and it overwrites this parameter value
>    with a XmlParser instance.
> 
>    The xml file should be located under:
>    data/testedBusinessRequest/testMethodName.xml
>    """
>    def __init__(self, testedBusinessRequest = ''):
>        self.testedBusinessRequest =\
>                testedBusinessRequest.lower()
> 
> 
>    def _getXmlParser(self, xml):
>        documentElement = XmlParser.parseXmlStream(xml)
>        parser = XmlParser.getParser(documentElement)
>        return parser
> 
> 
>    def __call__(self, method):
> 
>        # TODO: error handling here
>        methodName = method.func_code.co_name
>        methodName = methodName.split('_')[1]
> 
>        xmlFolder = self.testedBusinessRequest
>        xmlFile = '%s.xml' % methodName
> 
>        path = os.path.join(PATH, 'data',
>                xmlFolder, xmlFile)
> 
>        f = open(path)
>        xml = f.read()
>        f.close()
>        method.func_defaults = (self._getXmlParser(xml),)
>        return method
> 
> 
> class MyAppTest(unittest.TestCase):
> 
>    def setUp(self):
>        self.database = Database()
> 
>    def tearDown(self):
>        pass
> 
> 
> * test_Login.py - test a business request *
> from MyAppTest import MyAppTest, setup
> 
> from MyApp import Login
> 
> 
> class TestLogin(MyAppTest):
>    testedBusinessRequest = 'Login'
> 
>    @setup(testedBusinessRequest)
>    def test_validParameters(self, parser = None):
>        response = Login(self.database, parser).run()
>        return True
> 
> 
> 
> Ok, so the decorator setup should fill the parser parameter with a 
> XmlParser object. This works well if I add a __main__ and use unittest 
> to run the tests. But if I use nose, I get the following error:
> 
> *TypeError: unbound method __call__() must be called with setup instance 
> as first argument (got module instance instead)*
> 
> Any advices?

Nose works via the func_name parameter of a method/function.

So when you decorate it, you need to make sure that is set properly. One 
option is to do something like this:


from functools import wraps

def my_decorator(f):
    @wraps(f)
    def _d(*args, **kwargs):
        return f(*args, **kwargs)

    return _d


Diez



More information about the Python-list mailing list