【问题标题】:Meaning of unittest.main() in Python unittest modulePython unittest 模块中 unittest.main() 的含义
【发布时间】:2014-01-26 09:08:56
【问题描述】:

我正在尝试学习 Python 中的单元测试,特别是 unittest 模块。

考虑以下几行:

import unittest

class abc(unittest.TestCase):
    def xyz():
      ...

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

由于调用了unittest.main(),我可以看到我所有的测试用例都在运行。

我只是想知道这个调用是如何让所有测试用例运行的。

我知道,因为每个测试类都从 unittest.TestCase 继承,所以它正在发挥所有魔力。有什么见解吗?

【问题讨论】:

  • 它只是遍历unittest.TestCase的所有子类。你的问题到底是什么?它如何找到所有子类?

标签: python unit-testing python-internals


【解决方案1】:
unittest 关联的

main 实际上是 TestProgram 的一个实例,它在实例化时会运行您的所有测试。

以下是从http://pythonhosted.org/gchecky/unittest-pysrc.htmlunittest源复制的相关代码:

735  class TestProgram:
752 -    def __init__(self, module='__main__', defaultTest=None,
753                   argv=None, testRunner=None, testLoader=defaultTestLoader):
754          if type(module) == type(''):
755              self.module = __import__(module)
756              for part in module.split('.')[1:]:
757                  self.module = getattr(self.module, part)
758          else:
759              self.module = module
760          if argv is None:
761              argv = sys.argv
762          self.verbosity = 1
763          self.defaultTest = defaultTest
764          self.testRunner = testRunner
765          self.testLoader = testLoader
766          self.progName = os.path.basename(argv[0])
767          self.parseArgs(argv)
768          self.runTests()
769
770 -    def usageExit(self, msg=None):
771          if msg: print msg
772          print self.USAGE % self.__dict__
773          sys.exit(2)
774
775 -    def parseArgs(self, argv):
776          import getopt
777          try:
778              options, args = getopt.getopt(argv[1:], 'hHvq',
779                                            ['help','verbose','quiet'])
780              for opt, value in options:
781                  if opt in ('-h','-H','--help'):
782                      self.usageExit()
783                  if opt in ('-q','--quiet'):
784                      self.verbosity = 0
785                  if opt in ('-v','--verbose'):
786                      self.verbosity = 2
787              if len(args) == 0 and self.defaultTest is None:
788                  self.test = self.testLoader.loadTestsFromModule(self.module)
789                  return
790              if len(args) > 0:
791                  self.testNames = args
792              else:
793                  self.testNames = (self.defaultTest,)
794              self.createTests()
795          except getopt.error, msg:
796              self.usageExit(msg)
797
798 -    def createTests(self):
799          self.test = self.testLoader.loadTestsFromNames(self.testNames,
800                                                         self.module)
801
802 -    def runTests(self):
803          if self.testRunner is None:
804              self.testRunner = TextTestRunner(verbosity=self.verbosity)
805          result = self.testRunner.run(self.test)
806          sys.exit(not result.wasSuccessful())
807
808  main = TestProgram

因此,当您执行 unittest.main() 时,将创建一个 TestProgram 的对象,该对象在第 768 行调用 self.runTests()。构造函数还将您当前的文件作为包含测试的默认模块 (module='__main__')。

runTests() 被调用时,它又会调用self.testrunner.run()。当你参考TextTestRunner类的“run”方法时,你会发现它实际运行并报告了你所有的测试结果。

当您调用 unittest.main() 时,测试发现由 TestProgram.parseArgs 在第 775 行完成。第 798 行的self.createTests 实际上负责发现所有测试用例并创建测试套件。这就是所有的魔法。

【讨论】:

  • 再往下看,你会发现用于在loadTestsFromModule()loadTestsFromName() 方法中查找loader.py 中所有测试用例的循环。它遍历模块中的所有元素并应用检查issubclass(obj, case.TestCase) 来查找测试用例。
【解决方案2】:

在内部,unittest.main() 正在使用一些技巧来找出包含对 main() 的调用的模块(源文件)的名称。

然后它导入这个模块,检查它,获取所有可以测试的类和函数的列表(根据配置),然后为它们中的每一个创建一个测试用例。

当列表准备好后,它会依次执行每个测试。

【讨论】:

  • 这里的内部是什么意思,能解释一下吗?
  • 那么,如果我在继承 unittest.TestCases 的类中有几个方法,那么一旦调用 unittest.main(),这些函数就会一个接一个地被调用?
  • @Tyto 方法需要以test_ 开头,但是可以。该文档有很多示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 2015-10-16
  • 2017-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多