wiki:UnitTests

Version 5 (modified by toby, 13 years ago) (diff)

--

The hope is that all sections of GSAS-II computation aka "model" code (as opposed to controller or view code in the MVC paradigm) will eventually have unit tests, as described below.

Design philosophy

The goal is that the unit tests will exercise as much possible code as can be managed. Unit tests are expected to change and expand as code is augmented. Unit tests have several roles:

  • to insure that module interfaces remain static, so that downstream code is not broken by changes in a module
  • to validate computations against independently derived values (from other software or reference materials)
  • to confirm that results are platform independent
  • to catch software bugs as code is augmented and adapted

Where possible, unit tests should be both comprehensive and quick.

Implementation

Tests are to be included directly in the GSAS-II module by defining test functions. The test functions should be named to start with the string "test" and should not require any arguments. The test could should use assert or raise to report an unexpected result and should not print anything if the test succeeds. If the test requires more input than can comfortably be included in the module itself, the input should be placed in directory testinp\. If routines are used to generate this input, the generating routines can also be placed there. The code to implement the test can then look like this:

def test1():
    ''' test #1: SpcGroup and SGPrint against previous results'''
    testdir = ospath.join(mypath,'testinp')
    if ospath.exists(testdir):
        if testdir not in sys.path: sys.path.insert(0,testdir)
    import spctestinp
    def CompareSpcGroup(spc, referr, refdict, reflist): 
        'Compare output from GSASIIspc.SpcGroup with results from a previous run'
        #...
    for spc in spctestinp.SGdat:
        CompareSpcGroup(spc, 0, spctestinp.SGdat[spc], spctestinp.SGlist[spc] )

This allows the python nosetests to perform tests on the module using command nosetests <file.py> to run the test on the file (file.py). It is also convenient if the tests are implemented in a code section that is run if the file is run directly, rather than imported,

if __name__ == '__main__':
    test0()
    test1()
    test2()
    test3()
    print "OK"

this allows command python <file.py> to run the test without the nosetests package.

Finally, file unit_tests.py is intended to have a comprehensive list of all unit tests in GSAS-II, so that the entire suite of tests can be run in one pass. This file should contain a set of routines, each named beginning with the string "test" to exercise the self-tests from each module. Where this code:

import GSASIIspc
def test_GSASIIspc():
    GSASIIspc.test0()
def test_GSASIIspc1():
    GSASIIspc.test1()
def test_GSASIIspc2():
    GSASIIspc.test2()
def test_GSASIIspc3():
    GSASIIspc.test3()

duplicates that in the previous section. The contents of unit_tests.py will be run automatically if nosetests is run without arguments. To allow comprehensive testing without nosetests, adding the tests also in a section that is run when the unit_tests.py file is invoked rather than imported makes this too possible:

if __name__ == '__main__':
    test_GSASIIspc()
    test_GSASIIspc1()
    test_GSASIIspc2()
    test_GSASIIspc3()
    print "OK"