Changes between Version 10 and Version 11 of TestingGuidelines

Show
Ignore:
Timestamp:
01/21/07 05:59:43 (6 years ago)
Author:
jarrod.millman
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • TestingGuidelines

    v10 v11  
    22[[PageOutline]] 
    33= Introduction = 
    4 !SciPy's testing structure relies on the [http://projects.scipy.org/scipy/numpy/browser/trunk/numpy/testing NumPy testing system], which is based on the unit testing framework offered by [http://docs.python.org/lib/module-unittest.html unittest.py]. 
     4!SciPy uses the [http://projects.scipy.org/scipy/numpy/browser/trunk/numpy/testing NumPy testing system], which is based on the unit testing framework offered by [http://docs.python.org/lib/module-unittest.html unittest.py]. Our goal is that every module and package in !SciPy should have a thorough set of unit tests. These tests should exercise the full functionality of a given routine as well as its robustness to erroneous or unexpected input arguments. The best time to write the tests is when the module itself is being written. In addition, whenever a new bug is found in a routine, a new test for that specific case should be written and added to the test suite to prevent that bug from creeping back in unnoticed. 
    55 
    6 Our goal is that every module and package in !SciPy includes a thorough set of unit tests. These tests should exercise the functionality of a routine as well as its robustness to erroneous or unexpected input arguments. The best time to write the tests is when the module itself is being written. Whenever a new bug is found in a routine, a unit test should be written to test for the error so that it can't creep back in unnoticed after future code changes. 
    7  
    8 == Running !SciPy's test suite == 
    9 To run tests on the {{{scipy}}} package, use the following: 
     6To run !SciPy's full test suite, use the following: 
    107{{{ 
    118>>> import scipy 
    129>>> scipy.test() 
    1310}}} 
    14 This runs through the set of tests suite for !SciPy. If you are only interested in testing a subset of !SciPy, for example, the {{{integrate}}} module, use the following: 
     11The test method may take two arguments; the first specifies the level of testing and the second the verbosity. The higher the level the more test will be run. If the verbosity is 1 or less, the tests will just show information messages about the tests that are run; but if it is greater than 1, then the tests will also provide warnings on missing tests. So if you want to run every test and get messages about which modules don't have tests: 
     12{{{ 
     13>>> scipy.test(level=10, verbosity=2) # or 
     14>>> scipy.test(10, 2) 
     15}}} 
     16Finally, if you are only interested in testing a subset of !SciPy, for example, the {{{integrate}}} module, use the following: 
    1517{{{ 
    1618>>> scipy.integrate.test() 
    1719}}} 
    18  
    19 === Levels and verbosity === 
    20 The test method may takes two arguments; the first specifies the level of testing and the second the verbosity: 
     20The rest of this page will give you a basic idea of how to add unit tests to modules in !SciPy. It is extremely important for us to have extensive unit testing since this code is going to be used by scientists and researchers and is being developed by a large number of people spread across the world. So, if you are writing a package that you'd like to become part of !SciPy, please write the tests as you develop the package. Also since much of !SciPy is legacy code that was originally written without unit tests, there are still several modules that don't have tests yet. To see what modules still lack tests use: 
    2121{{{ 
    22 >>> scipy.test(level=1, verbosity=2) 
     22>>> scipy.test(level=0, verbosity=2) # or 
     23>>> scipy.test(0, 2) 
    2324}}} 
    24 The test level can be varied from 1 to 10. Increasing the verbosity provides more detailed messages about what tests are being executed. 
    25 {{{ 
    26 level: 
    27   None           --- do nothing, return None 
    28   < 0            --- scan for tests of level=abs(level), 
    29                      don't run them, return TestSuite-list 
    30   > 0            --- scan for tests of level, run them, 
    31                      return TestRunner 
    32  
    33 verbosity: 
    34   >= 0           --- show information messages 
    35   > 1            --- show warnings on missing tests 
    36 }}} 
     25Please feel free to choose one of these modules to develop test for either after or even as you read through this introduction. 
    3726 
    3827== Writing your own tests == 
    39 Much of !SciPy is legacy code that was written without unit tests. As such, much of the functionality remains untested. However, more unit tests are being written all the time (and we encourage you to contribute). If you are writing a package that you'd like to become part of !SciPy, please write the tests as you develop the package. 
     28Ideally, every Python code, extension module, or subpackage in the !SciPy package directory should have a corresponding {{{test_<name>.py}}} file.  This file should define classes derived from the {{{NumpyTestCase}}} (or the {{{unittest.TestCase}}}) class and have names starting with {{{test_}}}. The methods of these classes whose names start with {{{bench_}}}, {{{check_}}}, or {{{test_}}}, are passed on to the {{{unittest}}} machinery. In addition, the value of the first optional argument of these methods determines the level of the corresponding test. (Default level is 1.) 
    4029 
    41 === Setting up a module for testing === 
    42 Every module or package requires two things for its testing to be included in the !SciPy test suite. 
    43  1. A test module -- Every directory in the !SciPy directory structure has a {{{tests/}}} sub-directory. The test module for {{{dir1/module_xxx.py}}} is named {{{dir1/tests/test_module_xxx.py}}}. 
    44  1. Two test routines -- Every module should have the functions {{{test()}}} and {{{test_suite()}}} defined. The first of these is used when running tests from the command line. The second returns a {{{unittest.TestSuite}}} object that can be used by other programs to test !SciPy. This is beneficial, for instance, in generating web pages that show how healthly the current version of !SciPy is. 
    45  
    46 === The ``__init__.py`` file === 
    47  
    48 {{{ 
    49 # 
    50 # Package ... - ... 
    51 # 
    52  
    53 from info import __doc__ 
    54  
    55   ... 
    56  
    57 from numpy.testing import NumpyTest 
    58 test = NumpyTest().test 
    59 }}} 
    60  
    61 === The ``tests/`` directory === 
    62  
    63 Ideally, every Python code, extension module, or subpackage in Scipy package directory should have the corresponding {{{test_<name>.py}}} file in {{{tests/}}} directory.  This file should define classes derived from {{{NumpyTestCase}}} (or from {{{unittest.TestCase}}}) class and have names starting with {{{test}}}. The methods of these classes which names start with {{{bench}}}, {{{check}}}, or {{{test}}}, are passed on to unittest machinery. In addition, the value of the first optional argument of these methods determine the level of the corresponding test. Default level is 1. 
    64  
    65 A minimal example of a {{{test_yyy.py}}} file that implements tests for a Scipy package module {{{scipy.xxx.yyy}}} containing a function {{{zzz()}}}, is shown below:: 
    66  
     30=== test_yyy.py === 
     31Suppose you have a !SciPy module {{{scipy/xxx/yyy.py}}} containing a function {{{zzz()}}}. To test this you would start by creating a test module called {{{test_yyy.py}}}. This test file should include a class that tests {{{zzz()}}}. The test class has test methods that test various aspects of {{{zzz()}}}. Within these test methods, {{{assert()}}} is used to test whether some case is true. If the assert fails, the test fails. The {{{NumpyTest().run()}}} function actually runs the test suite. A minimal example of a {{{test_yyy.py}}} file that implements tests for a Scipy package module {{{scipy.xxx.yyy}}}, is shown below: 
    6732{{{ 
    6833import sys 
     
    8752    NumpyTest().run() 
    8853}}} 
     54{{{NumpyTestCase}}} is derived from {{{unittest.TestCase}}} and it basically only implements an additional method {{{measure(self, code_str, times=1)}}}. Note that all classes that are inherited from {{{TestCase}}} class, are picked up by the test runner when using {{{testall}}}. For more detailed information on defining test classes see the official documentation for the [http://docs.python.org/lib/module-unittest.html Python Unit testing framework]. 
    8955 
    90 {{{NumpyTestCase}}} is derived from {{{unittest.TestCase}}} and it basically only implements an additional method {{{measure(self, code_str, times=1)}}}. 
     56=== The ``tests/`` directory === 
     57Rather than keeping the code and the tests in the same directory, we put all the tests for a given subpackage in a {{{tests/}}} subdirectory. For our example, if it doesn't all ready exist you will need to create a {{{tests/}}} directory in {{{scipy/xxx/}}}. So the path for {{{test_yyy.py}}} is {{{scipy/xxx/tests/test_yyy.py}}}. 
    9158 
    92 Note that all classes that are inherited from {{{TestCase}}} class, are picked up by the test runner when using {{{testoob}}}. 
    93  
    94 === Template for {{{test_module_xxx.py}}} === 
    95 The following code will give you a basic idea of how to add unit tests to your module in !SciPy. Suppose you have a module {{{scipy/stats/foo.py}}} that has a function sum(a) that should accept a 1-D array or a scalar value. Create a test module called {{{scipy/stats/tests/test_foo.py}}}. This test file should include a class that tests {{{sum()}}} and a couple of other functions, {{{test_suite()}}} and {{{test()}}}. The test class has test methods that test various aspects of {{{sum()}}}. Within these test methods, {{{assert()}}} is used to test whether some case is true. If the assert fails, the test fails. Again, see here for more detailed info on defining test classes. The {{{test_suite()}}} function combines all the test classes that live in this module together to form a test suite that can be used for testing. The {{{test()}}} function actually runs the test suite. This file should look something like this: 
     59Once the {{{scipy/xxx/tests/test_yyy.py}}} is written, its possible to run the tests by going to the {{{tests/}}} directory and typing: 
    9660{{{ 
    97 ... 
     61python test_yyy.py 
     62}}} 
     63Or if you add {{{scipy/xxx/tests/}}} to the Python path, you could run the tests interactively in the interpreter like this: 
     64{{{ 
     65>>> import test_yyy.py 
     66>>> test_yyy.test() 
    9867}}} 
    9968 
    100 === Template for {{{test()}}} and {{{test_suite()}}} in {{{module_xxx.py}}} === 
    101  
    102 Once the {{{test_foo.py}}} is written, its possible to run the tests by going to the {{{tests/}}} directory and typing: 
     69=== The {{{__init__.py}}} file === 
     70Usually however, adding the {{{tests/}}} directory to the python path isn't desirable. Instead it would better to invoke the test straight from the module {{{xxx}}}. To this end, simply place the following two lines at the end of your package's {{{__init__.py}}} file: 
    10371{{{ 
    104 python test_foo.py 
    105 }}} 
    106 Or if {{{tests/}} was put in the python path, you could run the tests interactively in the interpreter like this: 
    107 {{{ 
    108 >>> import test_foo.py 
    109 >>> test_foo.test() 
    110 }}} 
    111 Usually however, adding the {{{tests/}}} directory to the python path isn't desireable. It would be nice to invoke the test straight from the module {{{foo.py}}}. To this end, {{{test()}}} and {{{test_suite()}}} methods are added to the {{{foo.py}}} module also. They use a couple of helper functions that live in {{{scipy/common/scipy_test.py}}} to handle the messy work. Place the following two definitions at the end of your module: 
    112 {{{ 
    113 """ foo.py 
    114 """ 
    115  
    116 def sum(a): 
    117    ... 
    118  
    119 def test(): 
    120     from scipy.common.scipy_test import module_test 
    121     module_test(__name__,__file__) 
    122  
    123 def test_suite(): 
    124     from scipy.common.scipy_test import module_test_suite 
    125     return module_test_suite(__name__,__file__) 
     72from numpy.testing import NumpyTest 
     73test = NumpyTest().test 
    12674}}} 
    12775Now you can do the following to test your module: 
    12876{{{ 
    12977>>> import scipy 
    130 >>> scipy.common.foo.test() 
     78>>> scipy.xxx.test() 
    13179}}} 
    13280 
     
    13785# your tests are included and run automatically! 
    13886}}} 
    139 Testing packages is a little more work, but not bad. See {{{scipy/common/__init__.py}}}. 
    14087 
    14188== {{{numpy.testing}}} ==