Introduction:Software testing is a very boring thing, especially when testing software written by others,ProgramUsually only writeCodeI am not interested in "no innovation", such as document writing and software testing. In this case, why not let programmers add some code for testing when writing software to automate the testing process? In software engineering, this technology is called Automated unit testing. This article describes how to achieve this goal when developing software using python.
I. Software Testing
The development of large-scale software systems is a very complicated process. Many errors are generated due to human factors. Therefore, the software development process must have corresponding quality assurance activities, software testing is a key measure to ensure quality. As software entropy describes: A program begins with a well-designed state and gradually loses its original structure as new functions are added, eventually it becomes messy (in fact, a question mark must be added for the initial "good state ). The purpose of the test is actually very simple and attractive, that is, to write high-quality software and solve the software entropy problem.
Unfortunately, software developers rarely perform software tests during the coding process. Most software projects are only tested during the final acceptance. Some projects do not even have a test plan! With the increasing awareness of software quality, many software development organizations begin to turn to UML, CMM, RUP, XP and other software engineering methods, in order to improve the software quality and make the software development process more controllable, fortunately, these methods put forward strict requirements for testing, so that the role of testing in the software development process is truly reflected.
Software testing, as a system engineering, involves all aspects of the entire software development process and requires the joint efforts of managers, designers, developers and testers. As the main force in the software development process, today's programmers not only need to write implementation code, but also undertake the arduous task of unit testing. Therefore, they must adopt a new working mode:
- Compile and maintain a set of detailed unit test cases;
- Construct unit test and acceptance test cases before writing code;
- Write code based on the constructed test cases.
Unit Testing is responsible for verifying the smallest Software Design Unit (Module). It uses the module description in the software design document as a guide to test important program branches to detect errors in the module. Because the software module is not a separate program, a large amount of additional code must be written for unit testing, which increases the workload of developers, currently, a better way to solve this problem is to use the test framework. The testing framework is the key to unit testing using the XP method, especially when a large number of test cases need to be constructed, because if these tests are constructed and executed in a manual manner, it will certainly become a tedious and time-consuming job, and the testing framework can solve these problems well.
Python developers can use pyunit compiled by Steve Purcell as a unit test framework. By integrating unit tests into the pyunit test framework, python programmers can more easily add, manage, and execute test cases, and analyze test results. In addition, pyunit can be used for automatic unit testing (regression testing ).
Back to Top
Ii. Standardized Python Unit Testing
Testing is a continuous process throughout the entire development process. In a sense, the software development process is actually a testing process. As Martin Fowler said, "You shouldn't write a program before you know how to test the code. Once you have completed the program, the test code should also be completed. Unless the test is successful, you cannot think that you have compiled a program that can work. "
The basic principle of the test is to compare whether the expected results are the same as the actual execution results. If the results are the same, the test is successful. Otherwise, the test fails. To better understand the role of the pyunit automated testing framework, let's look at a simple example. Suppose we want to test the widget class in Example 1:
Example 1. widget. PY # class widget to be tested: def _ init _ (self, size = (40, 40): 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 manually Perform unit tests may write test code similar to Example 2,
Example 2. manual. pyfrom widget import widget # class testwidget: def testsize (Self): expectedsize = (40, 40); 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 is not difficult to find that this manual testing method has many problems. First of all, the writing of the test program does not follow certain standards. Ten programmers may write ten different test programs, if every Python programmer has his/her own methods for designing test classes, it would be too much trouble to maintain the classes tested. Second, you need to write a lot of auxiliary code to perform unit testing. In example 1, the code used for testing is even more than the code to be tested, which will undoubtedly increase the workload of Python programmers.
In order to make unit test code easier to understand by testing and maintenance personnel, the best solution is to let developers follow certain specifications to compile the code for testing, for Python programmers, pyunit is used to construct unit test cases. Currently, pyunit has been recognized by most Python developers and has become a de facto unit test standard. If pyunit is used for the same test, the test code is shown in Example 3:
Example 3. auto. pyfrom widget import widgetimport unittest # 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) # construct the 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 testing framework, the code used for testing has been changed accordingly:
- Use the import statement to introduce the unittest module.
- Let all the classes that run the test inherit from the testcase class. You can regard testcase as a set of methods for testing a specific class.
- Initialize the task before the test in the setup () method, and clear the task after the test in the teardown () method, setup () and teardown () all are methods defined in the testcase class.
- Call the assertequal () method in testsize () to compare the returned value of the getsize () method and the expected value in the widget class to ensure that the two values are equal. assertequal () it is also defined in the testcase class.
- Provides a global method named Suite (). pyunit calls the suit () method during the test execution to determine how many test cases need to be executed, we can regard testsuite as a container that contains all test cases.
Although it looks a bit complex, pyunit allows all Python programmers to use the same unit test method. The test process is no longer disordered, but ordered under the same specification, this is the biggest benefit of using the pyunit automated unit testing framework.
Back to Top
Iii. Automated Testing Framework pyunit
After a general understanding of the software testing theory and pyunit, the following examples are provided to introduce how Python programmers use pyunit to perform unit testing. All the code is debugged in Python 2.2.2, and the operating system uses Red Hat Linux 9.
Back to Top
3.1 Installation
The pyunit module is required for unit testing in Python. Python 2.1 and later versions use pyunit as a standard module. However, if you use older versions of Python, you have to install it on your own. You can download the latest pyunitsource code package on the pyunit website (http://sourceforge.net/projects/pyunit repository, which uses pyunit-1.4.1.tar.gz.
After downloading the pyunit package, run the following command to decompress it:
[Root @ Gary source] # tar xzvf pyunit-1.4.1.tar.gz |
The easiest way to use the pyunit module in a python program is to ensure that the file unittest. py and unittestgui. py is included in the search path of Python. This can be achieved by directly setting the pythonpath environment variable, or by executing the following command to copy them to the current search path of Python:
[Root @ Gary source] # cd pyunit-1.4.1 [root @ Gary pyunit-1.4.1] # Python setup. py install |
Back to Top
3.2 Test Case testcase
The most basic component in software testing is the test case. pyunit uses the testcase class to represent the test case and requires that all classes used for testing must inherit from the class. The test code implemented by the testcase subclass should be self-contained. That is to say, the test cases can be run independently or together with other test cases.
Testcase is regarded as the running entity of the test unit in the pyunit test framework. Python programmers can use it to derive custom test processes and methods (test units) and use the command and composite design modes, multiple testcase can also be combined into a set of test cases. When the pyunit test framework runs a test case, the setup (), runtest (), and teardown () methods defined by the testcase subclass are executed sequentially. The simplest test case only needs to overwrite runtest () method to execute specific test code, as shown in Example 4:
Example 4. static_single.pyimport unittest # class widgettestcase (unittest. testcase): def runtest (Self): widget = widget () self. assertequal (widget. getsize (), (40, 40 )) |
To construct an instance of the widgettestcase class in the pyunit test framework, the constructor should be called without any parameters:
Testcase = widgettestcase () |
A test case usually tests only one method in the software module and uses the override runtest () method to construct a test case. In pyunit, it is called a static method, to test multiple methods in the same software module, you usually need to construct multiple classes for testing, as shown in Example 5:
Example 5. static_multi.pyimport unittest # test case class widgetsizetestcase (unittest. testcase): def runtest (Self): widget = widget () self. assertequal (widget. getsize (), (40, 40) # test case class widgetresizetestcase (unittest. testcase): def runtest (Self): widget = widget () widget. resize (100,100) self. assertequal (widget. get size (), (100,100 )) |
Using the static method, Python programmers have to write a test class for each method to be tested (this class performs the test by overwriting the runtest () method ), and generate an object to be tested in each test class. When writing test cases for the same software module, the objects to be tested have the same initial state, therefore, the Python programmer using the above method has to perform the same initialization for the object to be tested in each test class, which is often a time-consuming and boring job.
A better solution is to use the dynamic method provided by pyunit to write only one test class to test the entire software module, so that the initialization of the object can be done in setup () the release of resources can be completed in the teardown () method, as shown in Example 6:
Example 6. dynamic. pyimport unittest # class widgettestcase (unittest. testcase): def setup (Self): Self. widget = widget () def teardown (Self): Self. widget. dispose () self. widget = none def testsize (Self): Self. assertequal (self. widget. getsize (), (40, 40) def testresize (Self): Self. widget. resize (100,100) self. assertequal (self. widget. get size (), (100,100 )) |
The biggest advantage of using dynamic methods is that the structure of the test class is very good, and all the code used to test a software module can be implemented in the same class. Dynamic methods no longer overwrite the runtest () method, but write multiple test methods for the test class (according to habits, these methods usually start with test ), when creating an instance of the testcase subclass, you must give the name of the test method to indicate which method of the test class should be called when running the test case for the pyunit test framework:
Sizetestcase = widgettestcase ("testsize") resizetestcase = widgettestcase ("testresize ") |
3.3 test case set testsuite
A complete unit test rarely executes only one test case. Developers usually need to write multiple test cases to fully test a software function, these related test cases are called a test case set and are represented by the testsuite class in pyunit.
After creating some instances of the testcase subclass as test cases, the next step is to use the testsuit class to organize them. The pyunit testing framework allows Python programmers to define a global function named Suite () in unit test code and use it as the entry to the unit test, pyunit calls it to complete the 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 and add all test cases in its initialization method (_ init:
Class widgettestsuite (unittest. testsuite): def _ init _ (Self): unittest. testsuite. _ init _ (self, map (widgettestcase, ("testsize", "testresize "))) |
In this way, you only need to return an instance of the class in the suite () method:
Def Suite (): Return widgettestsuite () |
If all the test methods in the test class are enabled using test, Python programmers can even construct a testsuite using 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 considered as a container of the testcase class to organize multiple test cases, so that multiple test cases can be automatically completed in one test. In fact, in addition to testcase, testsuite can also contain testsuite to form a larger test case set:
Suite1 = mysuite1.thetestsuite () suite2 = mysuite2.thetestsuite () alltests = unittest. testsuite (suite1, suite2 )) |
3.4 conduct testing
Writing Test Cases (testcase) and organizing them into test suite has only one ultimate goal: to implement the test and obtain the final result. Pyunit uses the testrunner class as the basic execution environment for test cases to drive the entire unit test process. Python developers generally use the texttestrunner class instead of the testrunner class for unit testing. The test result is displayed in text format:
Runner = unittest. texttestrunner () runner. Run (suite) |
Example 7 shows how to use testrunner to perform a test,
Example 7. text_runner.pyfrom widget import widgetimport unittest # class widgettestcase (unittest. testcase): def setup (Self): Self. widget = widget () def teardown (Self): Self. widget. dispose () self. widget = none def testsize (Self): Self. assertequal (self. widget. getsize (), (40, 40) def testresize (Self): Self. widget. resize (100,100) self. assertequal (self. widget. getsize (), (100,100) # test if _ name _ = "_ main _": # construct Test Set suite = unittest. testsuite () suite. addtest (widgettestcase ("testsize") suite. addtest (widgettestcase ("testresize") # run the test runner = unittest. texttestrunner () runner. run (suite) |
To perform this unit test, run the following command:
[Xiaowp @ Gary Code] $ Python text_runner.py |
The running result should be as follows, indicating that two test cases have been executed and both have passed the test:
.. ------------------------------------------------------------------------ Ran 2 tests in 0.000sok |
If you modify the data and simulate an error, the following result is displayed:
. F ============================================== === fail: testresize (_ main __. widgettestcase) -------------------------------------------------------------------- traceback (most recent call last): file "text_runner.py", line 15, in testresize self. assertequal (self. widget. getsize (), (200,100) file "/usr/lib/python2.2/unittest. PY ", line 286, in failunlessequal raise self. failureexception,/assertionerror : (100,100 )! = (200,100) ---------------------------------------------------------------------- ran 2 tests in 0.001 sfailed (failures = 1) |
By default, texttestrunner outputs the result to SYS. stderr, but if a file object is passed to the constructor when the texttestrunner class instance is created, the output result will be redirected to the file. Using the texttestrunner class is a good option for driving unit tests in the python interaction environment.
The pyunit module defines a global method named main, which can be used to easily convert a unit test module into a test script that can be run directly. Main () methods Use the testloader class to search for all test methods contained in this module and execute them automatically. If a Python programmer can name all the test methods according to the conventions (starting with test), add the following lines of code at the end of the test module:
If _ name _ = "_ main _": unittest. Main () |
Example 8 shows how to use the main () method to perform a test,
Example 8. main_runner.pyfrom widget import widgetimport unittest # class widgettestcase (unittest. testcase): def setup (Self): Self. widget = widget () def teardown (Self): Self. widget. dispose () self. widget = none def testsize (Self): Self. assertequal (self. widget. getsize (), (40, 40) def testresize (Self): Self. widget. resize (100,100) self. assertequal (self. widget. getsize (), (100,100) # test if _ name _ = "_ main _": unittest. main () |
To perform this unit test, run the following command:
[Xiaowp @ Gary Code] $ Python main_runner.py |
All test methods in the test class widgettestcase will be automatically executed. However, if you only want to execute the testsize () method, you can use the following command:
[Xiaowp @ Gary Code] $ Python main_runner.py widgettestcase. testsize |
If testsuite is defined in the unit test script, you can also specify the test set to be run. You can use the-H parameter to view all the parameters that may be used to run the script:
[Xiaowp @ Gary Code] $ Python main_runner.py-H |
To make unit tests more active, a graphical interface test script unittestgui is provided in the pyunit software package. run the following command to start the test tool and test all the test cases in the main_runner.py script:
[Xiaowp @ Gary Code] $ Python unittestgui. py main_runner |
The dynamic line interface of the test tool is shown in interface 1:
Figure 1. Graphic Testing Tool
Click Start to start all test cases. The test result is as follows:
Figure 2 Test Results
You can use the graphic interface to perform unit tests and query test results more conveniently. Pyunit will differentiate failed tests, specifying whether it is a failure or an error, and whether the failure is the expected result checked by the assert class method (such as assertequal, errors are caused by exceptions.
Back to Top
Iv. Summary
Testing is the key to ensuring software quality. New software development methods require programmers to write test cases before writing code, and continuously perform unit tests during software development, this minimizes the generation of defects (bugs. Software unit testing is the cornerstone of the XP method. The testing framework provides a unified specification for programmers to perform unit testing. Python programmers can use pyunit as an automatic unit testing framework during software development.
References
1. Download the code in this article:Code
2. You can go to the python website (Http://www.python.org) To learn about Python.
3. On the pyunit website (Http://sourceforge.net/projects/pyunitYou can download the latest pyunit software package and detailed user manual.
4. Kent Beck'sArticle"Simple Smalltalk testing: With patterns "(Http://www.xprogramming.com/testfram.htmThe basic principles of the test framework are discussed from the perspective of the design model.
5. On the extreme programming website (Http://www.xprogramming.com) To understand the basic principles and methods of the XP method.
reprinted statement: This article is transferred from http://www.ibm.com/developerworks/cn/linux/l-pyunit/index.html