How does Python's unittest module detect test cases?

前端 未结 3 473
执笔经年
执笔经年 2021-01-01 12:41

I was wondering when we run unittest.main(), how does Python know what subclasses unittest.Testcase has?

For example, if I add a class

3条回答
  •  感动是毒
    2021-01-01 13:32

    I wrote some code that attempts to do behave similarly to unittest.main() below. In summary, I iterate through the modules, and for the modules that don't start with the name 'unittest', I inspect its members. Then if those members is a class and is a subclass of unittest.TestCase, I parse through that class' members. Then if those class' members is a function or method that starts with 'test', I add it to the list of tests. The class object's __dict__ is used to introspect the methods/functions since using inspect.getmembers may show too much. Finally that list of tests is converted to a tuple and wrapped up as a suite. Then the suite is ran using the runner at verbosity level 2. Note that, of course, removing the regex that checks for 'test' at the beginning of a function/method name can be removed to include bar_test() to the list of tests if you don't want that restriction.

    #!/usr/bin/env python
    
    import unittest
    import inspect
    import sys
    import re
    
    class Foo(unittest.TestCase):
       @staticmethod
       def test_baz():
          pass
    
       @classmethod
       def test_mu(cls):
          pass
    
       def test_foo(self):
          self.assertEqual('foo', 'foo')
    
       def bar_test(self):
          self.assertEqual('bar', 'bar')
    
    class Bar:
       pass
    
    if __name__ == '__main__':
       runner = unittest.TextTestRunner(verbosity=2)
       tests = []
       is_member_valid_test_class = lambda member: inspect.isclass(member) and \
          issubclass(member, unittest.TestCase)
    
       for module_name, module_obj in sys.modules.items():
          if not re.match(r'unittest', module_name):
             for cls_name, cls in inspect.getmembers(
                module_obj, is_member_valid_test_class):
                for methname, methobj in cls.__dict__.items():
                   if inspect.isroutine(methobj) and re.match(r'test', methname):
                      tests.append(cls(methname))
    
       suite = unittest.TestSuite(tests=tuple(tests))
       runner.run(suite)
    

    The resulting output is:

    test_foo (__main__.Foo) ... ok
    test_baz (__main__.Foo) ... ok
    test_mu (__main__.Foo) ... ok
    
    ----------------------------------------------------------------------
    Ran 3 tests in 0.001s
    
    OK
    

提交回复
热议问题