Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meaning of unittest.main() in Python unittest module

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?

like image 740
zephyr Avatar asked Jan 08 '14 10:01

zephyr


People also ask

What is unittest module in Python?

Python unittest module is used to test a unit of source code. Suppose, you need to test your project. You know what kind of data the function will return. After writing huge code, you need to check it whether the output is correct or not.

Is unittest a module?

The unittest module provides a rich set of tools for constructing and running tests. This section demonstrates that a small subset of the tools suffice to meet the needs of most users. A testcase is created by subclassing unittest.TestCase .

What is the use of unittest?

Unit testing allows the programmer to refactor code or upgrade system libraries at a later date, and make sure the module still works correctly (e.g., in regression testing). The procedure is to write test cases for all functions and methods so that whenever a change causes a fault, it can be quickly identified.


2 Answers

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.

like image 101
praveen Avatar answered Oct 06 '22 06:10

praveen


Internally, unittest.main() is using a few tricks to figure out the name of the module (source file) that contains the call to main().

It then imports this modules, examines it, gets a list of all classes and functions which could be tests (according the configuration) and then creates a test case for each of them.

When the list is ready, it executes each test in turn.

like image 24
Aaron Digulla Avatar answered Oct 06 '22 06:10

Aaron Digulla