Python Unit Test Framework UnitTest

Source: Internet
Author: User

Python Unit Test framework Author: Steve Purcell, <stephen_purcell at yahoo Dot com>
Translation: Heiz, Project website: http://pyunit.sourceforge.net/
Directory
    • Overview
    • System Requirements
    • Use Pyunit to build your own tests
      • Installation
      • Test Case Introduction
      • Create a simple test case
      • Multiplexing Setup codes: Creating firmware
      • Test case classes that contain multiple test methods
      • Aggregating test cases into test suites
      • Nested test Cases
      • Where to put the test code
      • Run tests interactively
      • To run a test from the command line
      • Run tests in the User Interface window
      • Writing a document for testing
      • More about test conditions
      • Testing for Equality
      • Test exception
    • Reusing old test code with Pyunit
    • Using Pyunit in Jpython and Jython
    • Precautions
      • Assertion
      • Memory usage
    • Terms of Use
    • Future plans
    • Updates and Community
    • Acknowledgement
    • Related information
    • About the author
Overview

The Python Unit test framework (the Python Unit Testing framework), referred to as Pyunit, is the JUnit python version designed by Kent Beck and Erich Gamma, the two clever guys. JUnit is also the Java version of the Kent-designed Smalltalk test framework. They are standard test frameworks for their respective languages.

This document only describes the design and use of unit test pyunit for Python. For background information on basic design of unit test framework, please refer to Kent's original article "Simple Smalltalk testing:with Patterns".

Since Python version 2.1, Pyunit has become part of the Python standard library.

The following defaults to what you already know about Python. I think Python is very simple and easy to learn and addictive.

System Requirements

Pyunit can be run on Python 1.5.2 and later versions.

The authors have tested Pyunit on Linux (Redhat 6.0 and 6.1 and Debian Potato) and Python 1.5.2, 2.0 and 2.1. And Pyunit is known to work on other operating system platforms, such as Windows and Macs. If you're having trouble with any system platform or Python version, let me know.

For details on using Pyunit in Jpython and Jython, read the Using Pyunit section in Jpython and Jython.

Use Pyunit to build your own test installation

The classes required to write tests can be found in the "UnitTest" module. This module is part of the standard library for Python 2.1 and later. If you are using an earlier version of Python, you should get this module from a separate pyunit release.

To make this module work in your code, you only need to make sure that the directory containing the "unittest.py" file is in your Python search path. To do this, you can modify the environment variable "$PYTHONPATH" or put the file in one of the directories in the current Python search path, such as a directory in the Redhat Linux system /usr/lib/python1.5/site-packages .

Note that you only have to do this work to run Pyunit's own example, unless you copy "unittest.py" to the example directory.

Test Case Introduction

Unit tests are made up of a number of test case (Cases) constructs. Test cases are separate scenarios that are set up to detect correctness. In Pyunit, the unittest classes in the module TestCase represent test cases.

TestCaseAn instance of a class is an object that can fully run test methods and optional settings (set-up) and clear (tidy-up) code.

TestCaseThe test code for an instance must be self-contained, in other words, it can run alone or in conjunction with any number of other test cases.

Create a simple test case

runTestThe simplest test example class can be obtained by overriding the method to run some test code:

        Import UnitTest        class Defaultwidgetsizetestcase (unittest. TestCase):            def runtest (self):                widget = Widget ("The widget")                assert widget.size () = = (50,50), ' incorrect Default Size '    

Note: For testing, we just used the python built-in "assert" statement. If the assertion (assertion) is false when the test case is run, the AssertionError exception is thrown, and the test framework considers the test case to be unsuccessful. Exceptions thrown by other non-"assert" checks are considered "errors" by the test framework. (see "More about test conditions")

The method for running the test case is described later. Now we're just creating an instance of a test case by calling the parameterless constructor (constructor):

        TestCase = Defaultwidgetsizetestcase ()    
Multiplexing Setup codes: Creating firmware

Now, the number of such test cases is huge and their setup requires a lot of repetitive work. In the above test case, if you create a "widget" in each of the 100 widget test cases, it can cause unsightly duplication.

Fortunately, we can extract these setup codes and place them in a setUp hook method called hooks. The test framework calls this method automatically when you run the test:

        Import UnitTest        class Simplewidgettestcase (unittest. TestCase):            def setUp (self):                self.widget = Widget ("The widget")        class Defaultwidgetsizetestcase ( Simplewidgettestcase):            def runtest (self):                assert self.widget.size () = = (50,50), ' incorrect default size '        class Widgetresizetestcase (simplewidgettestcase):            def runtest (self):                self.widget.resize (100,150)                assert self.widget.size () = = (100,150),                        ' wrong size after resize '    

If setUp the method throws an exception while the test is running, the framework considers the test to have encountered an error and runTest will not be executed.

Similarly, we can also provide a tearDown way to complete the runTest cleanup work after the run:

        Import UnitTest        class Simplewidgettestcase (unittest. TestCase):            def setUp (self):                Self.widget = Widgets ("The widget")            def TearDown (self):                Self.widget.dispose ()                self.widget = None    

If setUp the execution succeeds, the runTest method is executed regardless of success tearDown .

Such a working environment for the testing code is termed a fixture. The operating environment of this test code is called firmware (fixture, translator Note: This is a tentative translation, meaning a fixed component or method).

Test case classes that contain multiple test methods

Many small test cases often use the same firmware. In this use case, we end up SimpleWidgetTestCase producing many classes that contain only one method, such as DefaultWidgetSizeTestCase . This is time-consuming and not encouraged, so with JUnit's style, Pyunit provides a much easier way to:

        Import UnitTest        class Widgettestcase (unittest. TestCase):            def setUp (self):                Self.widget = Widgets ("The widget")            def TearDown (self):                Self.widget.dispose ()                self.widget = None            def testdefaultsize (self):                assert self.widget.size () = = (50,50) , ' Incorrect default size '            def testresize (self):                self.widget.resize (100,150)                assert Self.widget.size ( ) = = (100,150),                        ' wrong size after resize '    

In this use case, we did not provide a runTest method, but two different test methods. class instances will create and destroy individual self.widget and run a test method. When creating an instance of a class, we must indicate which test method will be run by passing the name of the method to the constructor:

        Defaultsizetestcase = Widgettestcase ("testdefaultsize")        resizetestcase = Widgettestcase ("TestResize")    
Aggregating test cases into test suites

Test case instances can be grouped together according to the characteristics they are testing. Pyunit provides a mechanism for this to be called "Test suite". It unittest is represented by the classes in the module TestSuite :

        Widgettestsuite = UnitTest. TestSuite ()        widgettestsuite.addtest (Widgettestcase ("Testdefaultsize"))        Widgettestsuite.addtest ( Widgettestcase ("Testresize"))    

As we'll see later, providing a callable object in each test module that returns a test suite that has been created is a good way to make testing easier:

       Def suite ():           suite = UnitTest. TestSuite ()           suite.addtest (Widgettestcase ("Testdefaultsize"))           Suite.addtest (Widgettestcase ("Testresize") ))           return Suite    

Can even be written as:

       Class Widgettestsuite (UnitTest. TestSuite):           def __init__ (self):               unittest. Testsuite.__init__ (Self,map (Widgettestcase,                                                     ("Testdefaultsize",                                                      "Testresize")))    

(Admittedly, the second method is not for the timid)

Because it is a common pattern to create a subclass of a test method that contains many similar names, the TestCase unittest module provides a convenient way to makeSuite create a test suite that consists of all the test cases in the test case class:

       Suite = Unittest.makesuite (widgettestcase, ' test ')    

It is important to note that when makeSuite you use a method, the order in which the test suite runs each test case is determined by the order in which the test method name is sorted according to the Python built-in function cmp .

Nested test suites

We often want to combine some test suites to test the entire system at once. This is simple, because multiple TestSuite can be added to another TestSuite , just as many TestCase are added in one TestSuite :

       Suite1 = Module1. Thetestsuite ()       suite2 = Module2. Thetestsuite ()       alltests = UnitTest. TestSuite ((suite1, Suite2))    

In the published package, in the examples directory, "" alltests.py provides an example of using nested test suites

Test where code is placed

You can place test case definitions in the same module as the code being tested (for example, "widget.py"), but placing the test code in a separate module (such as "widgettests.py") has some advantages:

    • Test modules can be executed separately from the command line
    • Test code can be easily detached from the release code
    • Less temptation to change the test code to accommodate the code being tested, without sufficient justification
    • Test code should not be frequently modified relative to the code being tested
    • The code being tested can be refactored in more ways
    • Now that the C code test should be placed in a separate module, why not maintain that consistency?
    • If the test policy changes, there is no need to modify the test source code
Run tests interactively

The main purpose of our writing tests is to run them and check that our software is working properly. The test framework uses the "Testrunner" class to provide an environment for running tests. The most common testrunner is TextTestRunner that it can run tests in text mode and report results:

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

TextTestRunnerThe output is sent by default sys.stderr , but you can change the default mode by passing a different similar file (File-object) object to its constructor.

This is an ideal way to run tests in a Python interpreter session TextTestRunner .

To run a test from the command line

unittestThe module contains a main method that makes it easy to turn a test module into a script that can run tests. mainuse unittest.TestLoader classes to automatically find and load test cases within a module.

Therefore, if you have previously test* named the test method using the conventions, then you can insert the following code at the end of the test module:

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

This way, when you execute your test module from the command line, all of the tests it contains will be run. Use the "-H" option to run the module to see all available options.

To run any test from the command line, you can unittest run the module as a script and pass the test case name in the test suite that you want to execute as an argument to the script:

        % python unittest.py widgettests. Widgettestsuite    

Or

        % python unittest.py widgettests.makewidgettestsuite    

You can also specify a specific test (method) to execute on the command line. To run the subclass of the class in the "Listtests" module TestCase ListTestCase (see the "examples" subdirectory in the release package), you can execute the following command:

        % python unittest.py listtests. Listtestcase.testappend    

"Testappend" is the name of the test method that the test case instance will execute. You can execute the following code to create ListTestCase a class instance and perform all the "test*" test methods it contains:

        % python unittest.py listtests. Listtestcase    
Run tests in the User Interface window

You can also run your tests using a graphical window. It is Tkinter written in. On most platforms, this window tool is bundled with Python for publishing. It looks very similar to the JUnit window.

You simply run the following command to use the Test Run window:

        % python unittestgui.py    

Or

        % python unittestgui.py widgettests. Widgettestsuite    

It is important to note that the test name entered must be an TestCase object name that can be returned or an TestSuite instance of the class, and it cannot be a pre-created test name, because each test must be re-created each time it is run.

The use of window testing creates additional time overhead due to updating those windows. On my system, every 1000 tests, it will take more than seven seconds. Your consumption may be different.

Writing a document for testing

Typically, when the test runs, TestRunner its name is displayed. This name consists of the test case class name and the name of the test method being run.

But if you provide doc-string for the test method, the first line of doc-string is displayed when the test is run. This provides a handy mechanism for writing test documents:

        Class Widgettestcase (UnitTest. TestCase):            def testdefaultsize (self): "",                Check that widgets is created with correct default size "                " " Assert self.widget.size () = = (50,50), ' incorrect default size '    
More about test conditions

I previously suggested that you should use the Python built-in assertion mechanism to examine the conditions in your test cases, rather than using your own alternatives because they are assert simpler, more concise, and familiar to you.

However, it is worth noting that if the Python optimization option is turned on (generating a ". Pyo" bytecode file) while the test is running, the assert statement will be skipped, making the test case useless.

I wrote a method for those users who needed to use the Python optimization option assert_ and added it into the TestCase class. It has the same functionality as built-in and assert is not optimized for deletion, but uses more cumbersome and output error messages to help smaller:

        def runtest (self):            Self.assert_ (self.widget.size () = = (100,100), "size is wrong")    

I have also TestCase provided in the class failIf and failUnless two methods:

        def runtest (self):            Self.failif (Self.widget.size () <> (100,100))    

The test method can also fail make the test fail immediately by calling the method:

        def runtest (self):            ...            If not hasattr (something, "blah"):                self.fail ("Blah Missing")                # or just ' Self.fail () '    
Testing for Equality

The most common assertion is testing for equality. If the assertion fails, the developer usually wants to see the actual error value.

TestCaseContains a pair of methods assertEqual and assertNotEqual is used for this purpose (if you like, you can also use aliases: failUnlessEqual and failIfEqual ):

        def testsomething (self):            self.widget.resize (100,100)            self.assertequal (Self.widget.size, (100,100))    
Test exception

Tests often want to check for exceptions in an environment. If the expected exception is not thrown, the test will fail. This is easy to do:

        def runtest (self):            try:                self.widget.resize ( -1,-1)            except ValueError:                pass            Else:                Fail ("expected a ValueError")    

Typically, the expected exception source (the code that throws the exception) is a callable object; For this, TestCase there is a assertRaises method. The first two parameters of this method are exceptions and callable objects that should appear in the "except" statement. The remaining parameters are arguments that should be passed to the callable object.

        def runtest (self):            self.assertraises (ValueError, Self.widget.resize,-1,-1)    
Reusing old test code with Pyunit

Some users want to run the existing test code directly from the Pyunit without having to turn it into a TestCase subclass.

To do this, Pyunit provides a FunctionTestCase class. This TestCase subclass can be used to wrap existing test functions. Settings and cleanup functions can also be optionally packaged.

For the following test functions:

        Def testsomething ():            something = makesomething ()            assert something.name is not None            ...    

We can create an equivalent instance of a test case:

        TestCase = UnitTest. Functiontestcase (testsomething)    

If there are additional settings and cleanup methods that need to be called by a test case, you can do the following:

        TestCase = UnitTest. Functiontestcase (testsomething,                                             setup=makesomethingdb,                                             teardown=deletesomethingdb)    
Using Pyunit in Jpython and Jython

Although Pyunit is primarily written for "C" python, you can still use Jython to write Pyunit tests to test your Java or Jython software. This is preferable to writing junit tests with Jython. Pyunit can also work correctly with early versions of Jython, Jython 1.0 and 1.1.

Of course, Java does not contain the TK GUI interface, so Pyunit's Tkinter-based GUI is not working under Jython, but the text-based interface works correctly.

To use Pyunit's text interface in Jython, simply copy the standard C Python Library module file ', ', ' traceback.py linecache.py , ' and ' stat.py getopt.py to a location that can be referenced by Jpython. You can find these files in any C python release. (This is a standard library for C Python version 1.5.x and may not be available for other versions of Python)

Now you can write your Pyunit test exactly as you did in C Python.

Caveats Assertion

See the "More about test Conditions" section for precautions.

Memory usage

When an exception is thrown during a test suite run, the resulting trace (Traceback) object is saved so that the failure information can be formatted for output after the test run is finished. In addition to simplicity, another advantage of this is that the future GUI Testrunner can later view local and global variables that are stored in the traced object.

One possible side effect is that when running a test suite with a high frequency of failure, the amount of memory used to save all of these retrospective objects becomes an issue. Of course, if a lot of tests fail, memory consumption is only the least of your problems.

Terms of Use

You can freely use, change and republish this software in accordance with the free terms used by Python. I only ask for my name, email address and project URL to remain in the code and accompanying documentation, giving me respect as the original author.

I am writing this software in order to improve the quality of the world's software to contribute to the meager power; I don't ask for money to return. (This is not to say that I do not welcome sponsorship)

Future plans

A key future plan is to integrate the TK GUI with the Idle IDE, and welcome to join!

Beyond that, I don't have a huge plan to extend the functionality of this module. I make pyunit as simple as possible (I hope it can't be any easier) because I believe that some commonly used auxiliary modules, such as log file comparisons, are best written by the test writers themselves.

Updates and Community

News, updates and more are available on the project website.

Welcome to various comments, suggestions and error reports; just send me an email or a very small mailing list and post your comments. Now there are a lot of pyunit users, they all have the wisdom to share with you.

Acknowledgement

Many thanks to Guido and he disciples for the Python language. In tribute, I has written the following haiku (or 'pyku', if you'll):

Guido van Rossum
' gawky Dutchman ' gave birth to
Beautiful Python

I gratefully acknowledge the work of Kent Beck and Erich Gamma for their work on JUnit, which made the design of Pyunit a No-brainer.

Thanks also to Tim voght; I discovered after I had implemented pyunit the he had also implemented a ' pyunit ' module as part of the his ' Pywiki ' Wikiwik IWeb clone. He graciously gave me the go-ahead to submit my version to the community at large.

Many thanks to those who has written to me with suggestions and questions. I ' ve tried to add appropriate credits in the changes file in the download package.

Particular thanks to J¨¦rôme Marant, who packaged pyunit for Debian.

Related information
    • Pyunit website
    • Python website
    • "Simple Smalltalk testing:with Patterns" Kent Beck
    • JUnit website
    • Xprogramming.com--Extreme Programming Homepage
    • Extremeprogramming in WikiWikiWeb
    • Pywiki--Python WikiWikiWeb copied by Tim Voght
About the author

Steve Purcell is just a programmer at heart, working independently writing, applying and teaching Open Source software.

He recently acted as Technical Director for a web/wap start-up, but spends most of his time architecting and coding large Java Systems whilst counterproductively urging his java-skilled colleagues-take-up Python instead.

Steve Purcell, <stephen_purcell at yahoo Dot com>

$Id: pyunit.html,v 1.20 2001/08/08 07:22:16 Purcell EXP $

Python Unit Test Framework UnitTest

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.