Значение unittest.main() в модуле unittest Python
Я пытался изучить модульное тестирование в Python, в частности модуль unittest
.
Рассмотрим следующие строки:
import unittest
class abc(unittest.TestCase):
def xyz():
...
if __name__ == "__main__":
unittest.main()
Я мог видеть, что все мои тестовые сценарии запущены из-за вызова unittest.main()
.
Мне было просто интересно узнать, как этот вызов запускает все тестовые сценарии.
Я знаю, так как я наследую от unittest.TestCase
для каждого тестового класса, он делает все волшебство. Любые идеи?
Ответы
Ответ 1
Внутри unittest.main()
используется несколько трюков для определения имени модуля (исходного файла), содержащего вызов main()
.
Затем он импортирует эти модули, проверяет его, получает список всех классов и функций, которые могут быть проверками (в соответствии с конфигурацией), а затем создает тестовый пример для каждого из них.
Когда список будет готов, он будет выполнять каждый тест по очереди.
Ответ 2
main, связанный с unittest, фактически является экземпляром TestProgram, который при создании экземпляра запускает все ваши тесты.
Ниже приведен код, скопированный из источника unittest в http://pythonhosted.org/gchecky/unittest-pysrc.html:
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
, который вызывает self.runTests()
в строке 768. Конструктор также переносит ваш текущий файл в качестве модуля по умолчанию, содержащего тесты (module='__main__'
). Когда вызывается runTests()
, он, в свою очередь, вызывает self.testrunner.run()
. Когда вы ссылаетесь на метод "run" класса TextTestRunner
, вы обнаружите, что он действительно запускается и сообщает все ваши результаты теста. Открытие теста выполняется TestProgram.parseArgs
в строке 775, когда вы вызываете unittest.main(). self.createTests
в строке 798 фактически отвечает за обнаружение всех ваших тестовых примеров и создание набора тестов. Это все волшебство.