开发者

Own log file for every testcase / Get name of next testcase

开发者 https://www.devze.com 2023-02-02 09:32 出处:网络
I would like to setup a new log file for every testcase. Something like the following: import unittest

I would like to setup a new log file for every testcase. Something like the following:

import unittest
import logging

log = logging.getLogger()

class TestExample(unittest.TestCase):
    def setUp(self):
        next_testcase = ???
        self.hdl = logging.FileHandler(
                'testcase_%s.log' % next_testcase, mode='w')
        log.addHandler(self.hdl)

    def tearDown(self):
        log.removeHandler(self.hdl)

How can I fi开发者_运维问答nd out the name testcase?

Or how would you implement something like the above?


Tricky! :-)

The problem here is that you can't know which function is the next one to be called - not without interfering in the unittest code directly.

However, if it where possible to change each test case into another method, that would call a "setup" custom made for that test case, and then execute the original test case, it would be solved.

In other words: one need to automate the change of each test case in your declared class into another function that: executes a personalized set-up, and them perfoms the original test. This should be done at class creation time.

It may seem complicated, but it is rather a job fit for "metaclasses" - as we are just doing what they are meant for: customizing the class creation.

So, by changing the metaclass for your TestCase to one that check each item on the class - if it is a test (i.e., if its name starts with "test"), creates a new wrapper function that does the above functionality, you can get it going.

(There is one further step needed: since the method name, and the (object for the) original test method must remain the same once created, one intermediate function has to be created to preserve the closure for each test case. Else, the variables method_name and original_method in the code bellow would all be set for the name and contents of the last function in the class at the end of the for loop)

There you go:

# -*- coding: utf-8 -*-
import unittest
import logging

#template method:
def log_setup(self, name):
    #self.hdl = logging.FileHandler('testcase_%s.log' % name, mode='w')
    #log.addHandler(self.hdl)
    self.name = name


class MetaTestCase(type):
    def __new__(cls, cls_name, bases, dict):
        for name, item in dict.items():
            if name.startswith("test"):
                def scope_freezer(method_name, original_method):
                    def wrapper(self, *args, **kw):
                        log_setup(self, method_name)
                        return original_method(self, *args, **kw)
                    return wrapper
                dict[name] = scope_freezer(name, item)
        return type.__new__(cls, cls_name, bases, dict)


class TestExample(unittest.TestCase):
    __metaclass__ = MetaTestCase
    def test_a(self):
        print self.name

    def test_b(self):
        print self.name

    def tearDown(self):
        pass
        #log.removeHandler(self.hdl)

unittest.main()

(to simplify testing on my side, I commented out the actual logging lines - the "prints" are working fine -- any code in the log_setup function will be run with selfand name properly set.)

And of course, you can factor out this metclass in another module and just import it for use on your tests.




import unittest
import logging

def log_setup(self, name):
    print name


class TestExample(unittest.TestCase):

    def test_method_name(self):
        print self.method_name

    def __getattribute__(self, name):
        safe_getattr =  super(TestExample, self).__getattribute__

        if name.startswith("test_"):
            self.method_name = name
            log_setup(self, name)

        return safe_getattr(name)



if __name__ == "__main__":
    unittest.main()
0

精彩评论

暂无评论...
验证码 换一张
取 消