Meaning of unittest.main() in Python unittest module

python, python-internals, unit-testing

Solution

main associated with unittest is actually an instance of TestProgram which, when instantiated, runs all your tests.

Below is the relevant code copied from the unittest source at 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

So when you execute `unittest.main()`, an object of `TestProgram` gets created which calls `self.runTests()` at line 768. The constructor also takes your current file as the default module containing the tests ( `module='__main__'`).

When `runTests()` is called, it in turn calls `self.testrunner.run()`. When you refer to the "run" method of `TextTestRunner` class, you will find that it actually runs and reports all your test results.

Test discovery is done by `TestProgram.parseArgs` at line 775 when you call unittest.main(). `self.createTests` at line 798 is actually responsible for discovering all your test cases and creating a test suite. This is all the magic.

Problem

I was trying to learn unit testing in Python, specifically the `unittest` module. Consider the following lines: ``` import unittest class abc(unittest.TestCase): def xyz(): ... if __name__ == "__main__": unittest.main() ``` I could see all my test cases running because of the call to `unittest.main()`. I was just curious to know how this call is making all the test cases run. I know since I'm inheriting from `unittest.TestCase` for every test class, it is doing all the magic. Any insights?

Original source