Python's Unit Testing framework

Source: Internet
Author: User

First, software testing

The development of large-scale software system is a very complicated process, in which there are many errors caused by human factors, so the software must have corresponding quality assurance activities in the development process, and software testing is the key measure to ensure the quality. As the software entropy (software entropy) describes: A program from a well-designed state to start, with the new functions continue to join, the program gradually lost the original structure, and eventually become mess (in fact, the original "good state" to add a question mark). The purpose of the test is actually very simple and attractive, which is to write high-quality software and solve the problem of software entropy.

Unfortunately, software developers rarely do software testing during coding, and most software projects are tested only at final acceptance, and some projects don't even have a test plan at all! With the enhancement of software quality awareness, many software development organizations have turned to UML, CMM, RUP, XP and other software engineering methods, in order to improve software quality, and make the software development process more controllable, fortunately, these methods have put forward very strict requirements for testing, So that the role of testing in the software development process began to truly reflect.

As a system engineering, software testing involves all aspects of the whole software development process and requires the joint efforts of managers, designers, developers and testers. As a major force in the software development process, today's programmers, in addition to writing implementation code, also bear the daunting task of unit testing, and therefore must adopt a new mode of work:

    • Write and maintain an exhaustive set of unit test cases;
    • The unit test and acceptance test cases are constructed before the code is written;
    • Code is written according to the test case that is constructed.

Unit testing is responsible for validating the smallest software Design Unit (module), which uses the description of the module in the Software design documentation as a guide, and tests the important branch of the program to discover errors in the module. Because the software module is not a separate program, in order to do unit testing also must write a lot of extra code, so as to virtually increase the workload of developers, it is a better way to solve this problem is to use the test framework. The test framework is the key to unit testing with the XP approach, especially if you need to construct a large number of test cases, because if you build and execute these tests entirely by hand, it will become a time-consuming and tedious task, and the test framework will be a good solution to these problems.

Developers using the Python language can use the Pyunit written by Steve Purcell as a unit test framework, and by fusing unit tests into Pyunit's test framework, Python programmers can more easily add, manage, and execute test cases, And the test results are analyzed. In addition, automated unit testing (regression testing) can also be implemented using Pyunit.


II. specification of Python unit testing

Testing is a continuous process throughout the development process, in a sense, the process of software development is actually the testing process. As Martin Fowler says, "You shouldn't write a program until you know how to test the code." And once you have completed the program, the test code should also be completed. Unless the test is successful, you cannot assume that you have written a program that can work. "

The basic principle of testing is to compare whether the expected result is the same as the actual execution result, and if the test succeeds, the test fails. To better understand the role of Pyunit as an automated testing framework, let's look at a simple example, assuming we're testing the widget class in Example 1:

Example 1. widget.py# class Widget to be tested:    def __init__ (self, size = (+)):        self._size = size    def getsize (self): 
   return self._size    def resize (self, width, height):        if width  0  or height < 0:            raise ValueError, "Illegal size"        self._size = (width, height)    def dispose (self):        Pass

Python programmers who do unit tests by hand are likely to write test code like Example 2,

Example 2. Manual.pyfrom Widget Import widget# class Testwidget:    def testsize (self):        expectedsize = (+, +);        Widget = Widget ()        if widget.getsize () = = Expectedsize:            print "Test [Widget]: GetSize works perfected!        " else:            print "Test [Widget]: GetSize doesn ' t work!" # test if __name__ = = ' __main__ ':    myTest = Testwidget ()    mytest.testsize ()

It's easy to notice. There are many problems with this method of manual testing. First of all, the test program is written without a certain specification can be followed, 10 programmers are completely likely to write 10 different test programs, if each Python programmer has its own different methods of designing test classes, the light maintenance of the tested class is enough trouble, who still take care of the test class. Second, you need to write a lot of auxiliary code to do unit testing, and the code in Example 1 for testing is even more than the code being tested, which will undoubtedly increase the workload of Python programmers.

In order for the unit test code to be more easily understood by the test and maintenance staff, the best solution is to have the developer follow certain specifications to write code for testing, specifically to the Python programmer, to use the Pyunit Automated test framework to construct the unit test case. Currently, Pyunit has been recognized by most Python developers as a de facto unit test standard. If you use Pyunit for the same test, the test code will look like Example 3:

Example 3. Auto.pyfrom Widget Import Widgetimport unittest# performs the test class Widgettestcase (UnitTest. TestCase):    def setUp (self):        self.widget = Widget ()    def tearDown (self):        self.widget = None    def Testsize (self):        self.assertequal (Self.widget.getSize (), (40, 40) # Build Test set Def suite ():    suite = UnitTest. TestSuite ()    suite.addtest (Widgettestcase ("Testsize"))    return suite# Test if __name__ = = "__main__"    : Unittest.main (defaulttest = ' suite ')

After using the Pyunit Unit test framework, the code used for the test was changed accordingly:

    • Introduce the UnitTest module with the import statement.
    • Having all classes that perform tests inherit from the TestCase class, you can consider TestCase as a collection of methods that test a particular class.
    • Before the test is initialized in the Setup () method, and the Teardown () method performs the post-test cleanup work, setUp () and teardown () are all methods defined in the TestCase class.
    • In Testsize (), call the Assertequal () method, compare the return value of the GetSize () method in the Widget class with the expected value, ensure that both are equal, and assertequal () is also the method defined in the TestCase class.
    • Provides a global method called Suite (), which Pyunit calls the suit () method to determine how many test cases need to be executed in the process of executing the test, and can treat testsuite as a container that contains all the test cases.

While it may seem a bit complicated, pyunit makes it possible for all Python programmers to use the same unit test method, the testing process is no longer cluttered, but rather an orderly behavior under the same specification, which is the greatest benefit of using Pyunit as an automated unit testing framework.


Third, automatic test framework Pyunit

After a general understanding of software testing theory and Pyunit, here are some examples of how Python programmers can use Pyunit for unit testing. All the code is debugged under Python 2.2.2, and the operating system uses red Hat Linux 9.


3.1 Installation

The Pyunit module is required for unit testing in Python, and Python 2.1 and later versions will have Pyunit as a standard module, but if you are using an older version of Python, you will have to install it yourself. On the Pyunit website (http://sourceforge.net/projects/pyunit), you can download to Pyunit's latest source package, which uses pyunit-1.4.1.tar.gz.

After downloading the Pyunit package, perform the following command to decompress it:

[Email protected] source]# tar xzvf pyunit-1.4.1.tar.gz

To use the Pyunit module in a python program, The simplest approach is to ensure that the files unittest.py and unittestgui.py in the Pyuni package are included in the Python search path, either by setting the PYTHONPATH environment variables directly or by executing the following commands to copy them to the current search route of Python In diameter:

[[Email protected] source]# CD Pyunit-1.4.1[[email protected] pyunit-1.4.1]# python setup.py install


3.2 Test Case TestCase

The most basic component of a software test is the test case, which Pyunit uses the TestCase class to represent the test case and requires that all classes used to perform the test must inherit from the class. The test code implemented by the TestCase subclass should be self-contained, which means that the test case can run either individually or with other test case constituent collections.

TestCase is considered a running entity of the test unit in the Pyunit test framework, where Python programmers can derive custom test procedures and methods (test units), use command and composite design patterns, Multiple testcase can also be combined into a collection of test cases. Pyunit test framework when running a test case, the setup (), Runtest (), and teardown () methods defined by the TestCase subclass are executed sequentially, and the simplest test case simply overrides the Runtest () method to execute the specific test code. As shown in Example 4:

Example 4. Static_single.pyimport unittest# performs the test class Widgettestcase (UnitTest. TestCase):    def runtest (self):        widget = widget ()        self.assertequal (Widget.getsize (), (40, 40))

To construct an instance of the above Widgettestcase class in the Pyunit test framework, the constructor should be called without any arguments:

TestCase = Widgettestcase ()

A test case typically tests only one method in a software module, using the Overwrite Runtest () method to construct a test case called a static method in Pyunit, and if multiple methods in the same software module are to be tested, it is often necessary to construct several classes that perform the tests, as shown in Example 5:

Example 5. The test case for the Static_multi.pyimport unittest# Test GetSize () method is Class Widgetsizetestcase (unittest. TestCase):    def runtest (self):        widget = widget ()        self.assertequal (Widget.getsize (), (40, 40)) # Test Resize () Method of the Test case class Widgetresizetestcase (UnitTest. TestCase):    def runtest (self):        widget = widget ()        widget.resize (+)        self.assertequal ( Widget.getsize (), (100, 100))

Using static methods, Python programmers have to write a test class for each method to be tested (the class executes the test by overwriting the Runtest () method) and generate a test object in each test class. When writing test cases for the same software module, many times the object under test has the same initial state, so Python programmers using the above method have to do the same initialization for the object under test in each testing class, which is often a time-consuming and tedious task.

A better solution is to use the dynamic method provided by Pyunit, which only writes a test class to complete the test of the entire software module, so that the initialization of the object can be done in the setup () method, and the release of the resource can be done in the teardown () method, as shown in Example 6:

Example 6. Dynamic.pyimport unittest# performs the test class Widgettestcase (UnitTest. TestCase):    def setUp (self):        Self.widget = Widgets ()    def tearDown (self):        self.widget.dispose ()        Self.widget = None    def testsize (self):        self.assertequal (Self.widget.getSize (), (max))    def testresize ( Self):        self.widget.resize (self.assertequal) (        self.widget.getSize (), (100, 100))

The biggest benefit of adopting a dynamic approach is that the test class has a very good structure, and all the code used to test a software module can be implemented in the same class. The dynamic method no longer overwrites the Runtest () method, but instead writes multiple test methods for the test class (which, by habit, usually begins with test), must give the name of the test method when creating an instance of the TestCase subclass. To indicate to the Pyunit test framework which method in the test class should be called when the test case is run:

Sizetestcase = Widgettestcase ("testsize") Resizetestcase = Widgettestcase ("Testresize")
3.3 Test Case Set Testsuite

Complete unit testing rarely executes only one test case, and developers often need to write multiple test cases to perform a more complete test of a software feature, which is called a set of test cases, represented by the Testsuite class in Pyunit.

After you have created instances of some testcase subclasses as test cases, the next step is to use the Testsuit class to organize them. The Pyunit test framework allows Python programmers to define a global function called Suite () in the Unit test code and use it as a portal for the entire unit test, pyunit by invoking it to complete the entire test process.

Def suite ():    suite = UnitTest. TestSuite ()    suite.addtest (Widgettestcase ("Testsize"))    Suite.addtest (Widgettestcase ("Testresize"    )) Return Suite

You can also define a subclass of Testsuite directly and complete the addition of all the test cases in its initialization method (__INIT__):

Class Widgettestsuite (UnitTest. TestSuite):    def __init__ (self):        unittest. Testsuite.__init__ (self, map (widgettestcase,                                              ("Testsize",                                               "Testresize")))

This only requires one instance of the class to be returned in the Suite () method:

Def suite ():    return Widgettestsuite ()

If all the test methods in the class used for the test are open with test, the Python programmer can even construct a testsuite with the Makesuite () method provided by the Pyunit module:

Def suite ():    return Unittest.makesuite (widgettestcase, "test")

In the Pyunit test framework, the Testsuite class can be seen as a container for the TestCase class to organize multiple test cases so that multiple test cases can be automatically completed in one test. In fact, Testsuite can contain testsuite in addition to TestCase, which can form a larger set of test cases:

Suite1 = mysuite1. Thetestsuite () Suite2 = Mysuite2. Thetestsuite () alltests = UnitTest. TestSuite ((suite1, Suite2))
3.4 Implementation Testing

There is only one final goal for writing test cases (TestCase) and organizing them into test case sets (TestSuite): To implement the tests and get the final results. Pyunit uses the Testrunner class as the basic execution environment for test cases to drive the entire unit test process. Instead of using the Testrunner class directly, the Python developer uses its subclass Texttestrunner to complete the test and display the test results as text:

Runner = UnitTest. Texttestrunner () Runner.run (suite)

Examples of using Testrunner to implement tests are shown in Example 7,

Example 7. Text_runner.pyfrom Widget Import Widgetimport unittest# performs the test class Widgettestcase (UnitTest. TestCase):    def setUp (self):        Self.widget = Widgets ()    def tearDown (self):        self.widget.dispose ()        Self.widget = None    def testsize (self):        self.assertequal (Self.widget.getSize (), (max))    def testresize ( Self):        self.widget.resize (+)                self.assertequal (Self.widget.getSize (), (+))        # test if __name_ _ = = "__main__":    # Constructs test set    suite = UnitTest. TestSuite ()    suite.addtest (Widgettestcase ("Testsize"))    Suite.addtest (Widgettestcase ("Testresize"))        # Execute Test    runner = UnitTest. Texttestrunner ()    Runner.run (Suite)

To perform this unit test, you can use the following command:

[email protected] code]$ python text_runner.py

The running result should look like this, indicating that 2 test cases were executed, and both passed the test:

.. ----------------------------------------------------------------------Ran 2 tests in 0.000sOK

If the data is modified and the error is simulated, the following results will be obtained:

. F==========================================fail:testresize (__main__. Widgettestcase)----------------------------------------------------------------------Traceback (most recent call Last):  File ' text_runner.py ', line testresize    self.assertequal (Self.widget.getSize (), (max.))  File "/usr/lib/python2.2/unittest.py", line 286, in Failunlessequal    raise Self.failureexception, Assertionerror: ( , 2)! = (at $)----------------------------------------------------------------------Ran, tests in 0.001sFAILED (Failures=1)

By default, Texttestrunner outputs the results to sys.stderr, but if you pass a file object to the constructor when you create an instance of the Texttestrunner class, the output is redirected to the file. Using the Texttestrunner class is a good choice when driving unit tests in a python interactive environment.

The Pyunit module defines a global method called Main, which makes it easy to turn a unit test module into a test script that can be run directly, and the main () method uses the Testloader class to search all the test methods contained in the module and automatically executes them. If a Python programmer is able to name all the test methods by convention (beginning with test), simply add the following lines of code to the end of the test module:

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

An example of using the main () method to implement the test is shown in Example 8,

Example 8. Main_runner.pyfrom Widget Import Widgetimport unittest# performs the test class Widgettestcase (UnitTest. TestCase):    def setUp (self):        Self.widget = Widgets ()    def tearDown (self):        self.widget.dispose ()        Self.widget = None    def testsize (self):        self.assertequal (Self.widget.getSize (), (max))    def testresize ( Self):        self.widget.resize (+)        self.assertequal (Self.widget.getSize (), (+))   # test if __name_ _ = = "__main__":    Unittest.main ()

To perform this unit test, you can use the following command:

[email protected] code]$ python main_runner.py

All the test methods in the test class Widgettestcase will be executed automatically, but if you only want to execute the Testsize () method, you can use the following command:

[email protected] code]$ python main_runner.py widgettestcase.testsize

If Testsuite is defined in the unit test script, you can also specify the test set to run. Use the-h parameter to see all the possible parameters for running the script:

[email protected] code]$ python main_runner.py-h


Original address: http://www.ibm.com/developerworks/cn/linux/l-pyunit/



Python's Unit Testing framework

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.