Python的unittest模块如何检测测试用例?

2024-05-17 11:13:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我想知道当我们运行unittest.main()时,Python如何知道unittest.Testcase有哪些子类?

例如,如果我添加一个类FromRomanBadInput(unittest.TestCase),那么unittest如何知道运行这个类?


Tags: mainunittest子类testcasefromromanbadinput
3条回答

我编写了一些代码,试图在下面执行与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

“main”函数搜索导入模块中继承unittest.TestCase的所有类。和当前路径,然后尝试运行以“test”开头的每个方法

来自python's document

import random
import unittest

class TestSequenceFunctions(unittest.TestCase):

    def setUp(self):
        self.seq = range(10)

    def test_shuffle(self):
        # make sure the shuffled sequence does not lose any elements
        random.shuffle(self.seq)
        self.seq.sort()
        self.assertEqual(self.seq, range(10))

        # should raise an exception for an immutable sequence
        self.assertRaises(TypeError, random.shuffle, (1,2,3))

    def test_choice(self):
        element = random.choice(self.seq)
        self.assertTrue(element in self.seq)

    def test_sample(self):
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)

if __name__ == '__main__':
    unittest.main()

A testcase is created by subclassing unittest.TestCase. The three individual tests are defined with methods whose names start with the letters test. This naming convention informs the test runner about which methods represent tests.

所以我在我的Python27/Lib目录中四处寻找。。。

unittest.main实际上是类unittest.TestProgram的别名。因此,所发生的是构造一个这个实例,它的__init__运行,这将执行一系列健全性检查和配置,包括从中调用它的模块的动态导入(它使用__import__函数,默认情况下,__main__是要导入的模块的名称)。所以现在它有一个self.module属性,它包含一个表示源代码的模块对象。

最终,它得到了以下代码:

self.test = self.testLoader.loadTestsFromModule(self.module)

其中self.testLoaderunittest.TestLoader的实例。这种方法包括:

    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, case.TestCase):
            tests.append(self.loadTestsFromTestCase(obj))

因此,它使用module对象的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函数。我想这是为了避免获取嵌套类。)

相关问题 更多 >