Search code examples
pythonunit-testingpython-2.7nosetests

Append the nose @attr to the test name


I am able to setup nose tests to run with the @attr tag. I am now interested in know if I can append to the end of the test name, the @attr tag? What we are trying to do is add a tag if our tests run into an issue and we write up a defect for it, we would then put the defect number as an @attr tag. Then when we run we could easily identify which tests have open defects against them.

Just wondering if this is even possible, and where to go to see how to set it up?

EDIT RESULTS RUNNING WITH ANSWER:enter image description here enter image description here

Test Results: enter image description here

So I sort of know what is going on, if I have the @fancyattr() at the class level it picks it up and changes the name of the class. When I put the @fancyattr() at the test level it is not changing the name of the test, which is what I need for it to do.

For example - Changes the name of the class:

@dms_attr('DMSTEST')
@attr('smoke_login', 'smoketest', priority=1)
class TestLogins(BaseSmoke):

"""
Just logs into the system and then logs off
"""

def setUp(self):
    BaseSmoke.setUp(self)

def test_login(self):
    print u"I can login -- taking a nap now"
    sleep(5)
    print u"Getting off now"

def tearDown(self):
    BaseSmoke.tearDown(self)

This is what I need and it isn't working:

@attr('smoke_login', 'smoketest', priority=1)
class TestLogins(BaseSmoke):

    """
    Just logs into the system and then logs off
    """

    def setUp(self):
        BaseSmoke.setUp(self)

    @dms_attr('DMSTEST')  
    def test_login(self):
        print u"I can login -- taking a nap now"
        sleep(5)
        print u"Getting off now"

    def tearDown(self):
        BaseSmoke.tearDown(self)

Updated screenshot with what I am seeing with __doc__:

enter image description here


Solution

  • Here is how to do it with args type attributes:

    rename_test.py:

    import unittest 
    from nose.tools import set_trace
    
    def fancy_attr(*args, **kwargs):
        """Decorator that adds attributes to classes or functions
        for use with the Attribute (-a) plugin. It also renames functions!
        """
        def wrap_ob(ob):
            for name in args:
                setattr(ob, name, True)
                #using __doc__ instead of __name__ works for class methods tests
                ob.__doc__ = '_'.join([ob.__name__, name])
                #ob.__name__ = '_'.join([ob.__name__, name])
    
            return ob
    
        return wrap_ob
    
    
    class TestLogins(unittest.TestCase):
        @fancy_attr('slow')
        def test_method():
            assert True
    
    
    @fancy_attr('slow')
    def test_func():
        assert True
    

    Running test:

    $ nosetests rename_test.py -v
    test_method_slow ... ok
    test_func_slow ... ok
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.003s
    
    OK
    

    EDIT: For xunit reporting to work, test renaming should take place before running the test. You can do it on import, here is untested hack showing how to do it:

    rename_test.py:

    import unittest 
    
    def fancy_attr(*args, **kwargs):
        """Decorator that adds attributes to classes or functions
        for use with the Attribute (-a) plugin. It also renames functions!
        """
        def wrap_ob(ob):
            for name in args:
                setattr(ob, name, True)
                ob.__doc__ = '_'.join([ob.__name__, name])
    
            return ob
    
        return wrap_ob
    
    
    class TestLogins(unittest.TestCase):
        @fancy_attr('slow')
        def test_method(self):
            assert True
    
    
    def make_name(orig, attrib):
        return '_'.join([orig, attrib])
    
    def rename(cls):
        methods = []
        for key in cls.__dict__:
            method = getattr(cls, key)
            if method:
                if hasattr(cls.__dict__[key], '__dict__'):
                    if 'slow' in cls.__dict__[key].__dict__:
                        methods.append(key)
    
        print methods
    
        for method in methods:
            setattr(cls, make_name(method, 'slow'),  cls.__dict__[key])
            delattr(cls, method)
    
    
    rename(TestLogins)
    
    @fancy_attr('slow')
    def test_func():
        assert True