
Unit Testing Overview
=====================

The sancho.unittest module provides a framework for writing unit tests
for other Python code.


Structure for Test Scripts
--------------------------

Tests are grouped into test scenarios and test cases.  A test scenario
is a Python class containing a set of one or more test cases:

from sancho.unittest import TestScenario

class FuncTestScenario(TestScenario):
    def setup(self):
        ...
    def shutdown(self):
        ...
    def check_thing1(self):
        ...
    def check_thing2(self):
        ...

Each test case is a method containing one or more tests, which are
calls to one of the test_*() methods described in the following
section.

Functions in sancho.unittest
----------------------------

The sancho.unittest module provides several useful functions.
Commonly test scripts will contain a stereotyped main block containing
the following:

if __name__ == "__main__":
    (scenarios, options) = parse_args()
    run_scenarios(scenarios, options)

This block parses the command-line arguments passed to the test script
when it's being run directly, and runs the selected test scenarios.

find_scenarios(module)

Finds all test scenarios (subclasses of TestScenario) made available
by the module 'module' and returns the list of class objects found.
By default a scenario is considered available if it's defined in that
module.  To restrict the list of scenarios to a more limited set,
define a module global variable named 'test_scenarios', setting its
value to the desired list of test scenario classes.

parse_args( [argv] )

Parse the command-line arguments to a test script.  The optional
'argv' parameter is a list of strings containing the command-line
arguments; if omitted, the contents of sys.argv will be used.
Returns a tuple (scenarios, options); 'options' is a TestOptions
instance recording the -q/-v/etc. options; 'scenarios' is a list of
test scenario descriptions as required by run_scenarios().

run_scenarios(scenarios, [options=None] )

Runs a bunch of test scenarios.  'scenarios' is a list of test
scenario descriptions.  A test scenario description is either a single
class object, in which case all test cases in that test scenario are
run; or it is a tuple (test_scenario, ['case1', 'case2', ...]), where
'test_scenario' is again a class object and 'case1', 'case2', ... are
the names of the test cases to run.  Test case names are the same as
the method that implements the test case, with the leading
'check_' optionally lopped off.


TestScenario methods
--------------------

TestScenario.setup()

Subclasses of TestScenario must override this function to perform any
required initialization (creating objects, opening files, etc.).
Objects needed by test cases should be assigned to attributes of the
TestScenario instance; for example, self.file = open('foo', 'r') would
be used to open a file and assign the resulting object to the file
attribute.  This method will be called before each test case.


TestScenario.shutdown()

Subclasses of TestScenario must override this function to clean up
after running a test case, undoing the initialization done in the
setup() method.  This is done by deleting any attributes created by
setup().  This method will be called after each test case has been
completed.


TestScenario.test_bool(code, want_true=1)

Test whether the Boolean return value of the expression 'code' is
equivalent to the want_true flag.


TestScenario.test_exc(stmt, exc)

Execute the statement 'stmt', assuming it will raise the exception
'exc'.


TestScenario.test_seq(code, seqval,
                      match_types=0, match_order=1)

Test whether the expression 'code' returns a sequence that matches
'seqval'. If 'match_order' is false, the order of the sequence is
assumed to be irrelevant, so that only its contents matter.  If
'match_types' is true, then the contents of the sequence must have
exactly the same types.


TestScenario.test_stmt(stmt)

Execute the statement 'stmt', assuming it will run without raising an
exception.


TestScenario.test_val(code, value=None,
                      match_ident=0, match_types=0)

Test whether the expression 'code' returns 'value'. The optional
'match_ident' and 'match_types' flags allow enforcing object identity
or type identity.


The run_sancho_tests script
---------------------------

The run_sancho_tests script will run all test scripts for a
directory or for a directory tree, and report the results.  It works by
searching for any file named test_*.py in any subdirectory
named "test" under the current directory, or under an optional
starting directory supplied on the command line.

The command-line syntax is:
[-c] [-q|-v] [scenario1][:case1,...] ...

The '-c' switch enables measurement of code coverage.  

The '-q' (for ``quiet'') switch produces the minimum amount of output,
just the number of tests run and reports of any test failures, instead
of the default one line of output for every file executed.

The '-r' (for ``recursive'') switch causes the script to descend into
subdirectories of the starting directory.  


Examples
========

See the examples/ subdirectory in the Sancho source distribution for 
a simple example.
