@@ -14,9 +14,36 @@ Unit Testing revolves around the following principles:
This page is in no way meant to replace tutorials on Python's unittest module, for this we refer the reader to the `official documentation <http://docs.python.org/library/unittest.html>`_. We will however adress certain specificities about how unittests relate to theano.
Unittest Primer
===============
A unittest is a subclass of ``unittest.TestCase``, with member functions with
names that start with the string ``test``. For example:
>>> class MyTestCase(unittest.TestCase):
>>> def test0(self):
>>> pass # test passes cleanly
>>> def test1(self):
>>> self.failUnless(2+2 == 5) # raises an exception, causes test to fail
>>> def test2(self):
>>> assert 2+2 == 5 # causes error in test (basically a failure, but counted separately)
>>> def test2(self):
>>> assert 2+2 == 4 # this test has the same name as a previous one, so this is the one that runs.
How to Run Unit Tests ?
-----------------------
Two options are avaiable.
Nosetests
~~~~~~~~~
The easiest by far is to use ``nosetests`` which
is a command line utility that recurses through a given directory, finds all
unittests matching a specific criteria and executes them. By default, it will
find & execute tests case in test*.py files whose method name starts with 'test'.
To run just a single ``MyTestCase`` member test function called ``test0``:
>>> MyTestCase('test0').debug()
Folder Layout
-------------
...
...
@@ -198,13 +252,15 @@ following:
>>> def setUp(self):
>>> unittest_tools.seed_rng()
>>> # OR ... call with an explicit seed
>>> unittest_tools.seed_rng(234234)
>>> unittest_tools.seed_rng(234234) #use only if really necessary!
The behaviour of seed_rng is as follows:
* if the environment variable THEANO_UNITTEST_SEED is defined, it will be used to seed the random number generator (and override any seed provided by the user)
* if THEANO_UNITTEST_SEED is not defined, the user-supplied seed will be used to seed the rng
* if THEANO_UNITTEST_SEED is not defined and no seed is given, the rng will be seeded with a random seed.
* If an explicit seed is given, it will be used for seending numpy's rng.
* If not, it will try to get a seed from the THEANO_UNITTEST_SEED variable.
* If THEANO_UNITTEST_SEED is set to "random", it will seed the rng. with None, which is equivalent to seeding with a random seed.
* If THEANO_UNITTEST_SEED is not defined, it will use a default seed of 666.
The main advantage of using unittest_tools.seed_rng is that it allows us to
change the seed used in the unitests, without having to manually edit all the
...
...
@@ -213,13 +269,13 @@ changing the seed on every run (hence achieving a higher confidence that the
variables are correct), while still making sure unittests are deterministic.
Users who prefer their unittests to be random (when run on their local machine)
can simply undefine THEANO_UNITTEST_SEED.
can simply set THEANO_UNITTEST_SEED to 'random'.
Similarly, to provide a seed to numpy.random.RandomState, simply use:
>>> rng = numpy.random.RandomState(unittest_tools.fetch_seed(1231)) #again not recommended
Note that the ability to change the seed from one nosetest to another, is incompatible with the method of hard-coding the baseline variables (against which we compare the theano outputs). These must then be determined "algorithmically". Although this represents more work, the test suite will be better because of it.
...
...
@@ -249,14 +305,81 @@ is approximated as:
* calculate the gradient using the symbolic expression provided in the ``grad`` function
* compares the two values. The tests passes if they are equal to within a certain tolerance.