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

时间:2012-04-11 03:40:36

标签: python unit-testing

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

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

3 个答案:

答案 0 :(得分:30)

所以我环顾了Python27/Lib目录......

unittest.main实际上是类unittest.TestProgram的别名。那么你要构建一个这样的实例,并运行它__init__,它会进行一系列健全性检查和配置,包括动态导入你调用它的模块(它使用{{1} } function,默认情况下,__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派生的类(本地,{ {1}}是该别名的别名,然后在这些类中查找要添加到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 by默认)并且可以调用(依次具有self.testMethodPrefix属性)。 (我真的很惊讶他们在这里没有使用内置的'test'函数。我想这是为了避免使用嵌套类。)

答案 1 :(得分:7)

'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()
  

通过继承unittest.TestCase创建测试用例。他们三个   单个测试使用名称以。开头的方法定义   字母测试。这个命名约定告诉测试运行者   哪些方法代表测试。

答案 2 :(得分:0)

我编写了一些代码尝试执行类似于下面的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