我想知道当我们运行unittest.main()
时,Python是如何知道unittest.Testcase
有哪些子类的?
例如,如果我添加了一个类FromRomanBadInput(unittest.TestCase)
,unittest
如何知道要运行它?
发布于 2012-04-11 13:07:22
所以我查看了一下我的Python27/Lib
目录...
unittest.main
实际上是一个类unittest.TestProgram
的别名。因此,您构建了一个实例,它的__init__
将运行,该实例将执行一系列健全性检查和配置,包括动态导入从中调用它的模块(它使用__import__
函数,默认情况下使用__main__
作为要导入的模块的名称)。因此,现在它有一个self.module
属性,其中包含一个表示源代码的模块对象。
最后,它转到下面的代码:
self.test = self.testLoader.loadTestsFromModule(self.module)
其中self.testLoader
是unittest.TestLoader
的一个实例。该方法除了其他内容外,还包含:
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, case.TestCase):
tests.append(self.loadTestsFromTestCase(obj))
因此,它使用模块对象的dir
来获取您定义的所有全局变量(包括类)的名称,将其过滤为仅从unittest.TestCase
派生的类(在本地,case.TestCase
是该类的别名),然后在这些类中查找测试方法以添加到tests
列表中。该搜索的行为类似:
def isTestMethod(attrname, testCaseClass=testCaseClass,
prefix=self.testMethodPrefix):
return attrname.startswith(prefix) and \
hasattr(getattr(testCaseClass, attrname), '__call__')
testFnNames = filter(isTestMethod, dir(testCaseClass))
因此,它使用类的dir
来获取要尝试的名称列表,查找具有这些名称的属性,并选择以self.testMethodPrefix
开头的属性(缺省情况下为'test'
)和可调用的属性(具有__call__
属性)。(我真的很惊讶他们在这里没有使用内置的callable
函数。我猜这是为了避免拾取嵌套类。)
发布于 2016-07-13 21:18:45
我写了一些代码,试图实现与下面的unittest.main()类似的行为。总之,我遍历模块,对于不是以“unittest”开头的模块,我检查它的成员。然后,如果这些成员是一个类,并且是unittest.TestCase的子类,我将解析该类的成员。然后,如果这些类的成员是以“test”开头的函数或方法,我会将其添加到测试列表中。类对象的__dict__
用于内省方法/函数,因为使用inspect.getmembers可能会显示太多内容。最后,将测试列表转换为元组并包装为套件。然后在详细级别2使用运行器运行套件。当然,请注意,如果您不想要这个限制,可以删除函数/方法名称开头的检查'test‘的正则表达式,以便将bar_test()包含在测试列表中。
#!/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)
结果输出为:
test_foo (__main__.Foo) ... ok
test_baz (__main__.Foo) ... ok
test_mu (__main__.Foo) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
https://stackoverflow.com/questions/10099491
复制相似问题