EPICS Base  7.0.6.1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Functions
epicsUnitTest.h File Reference

Unit test routines. More...

#include <stdarg.h>
#include "compilerDependencies.h"
#include "libComAPI.h"
Include dependency graph for epicsUnitTest.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

LIBCOM_API void testPlan (int tests)
 Declare the test plan, required. More...
 
LIBCOM_API void LIBCOM_API int testDiag (const char *fmt,...) EPICS_PRINTF_STYLE(1
 Output additional diagnostics. More...
 
LIBCOM_API void LIBCOM_API int
LIBCOM_API int 
testDone (void)
 Mark the end of testing.
 
LIBCOM_API int testImpreciseTiming (void)
 Return non-zero in shared/oversubscribed testing environments. More...
 
Missing or Failing Tests

Routines for handling special situations.

LIBCOM_API void testSkip (int skip, const char *why)
 Place-holders for tests that can't be run. More...
 
LIBCOM_API void testTodoBegin (const char *why)
 Mark the start of a group of tests that are expected to fail. More...
 
LIBCOM_API void testTodoEnd (void)
 Mark the end of a failing test group.
 
LIBCOM_API void testAbort (const char *fmt,...) EPICS_PRINTF_STYLE(1
 Stop testing, program cannot continue. More...
 

Announcing Test Results

Routines that declare individual test results.

#define testOk1(cond)   testOk(cond, "%s", #cond)
 Test result using expression as description. More...
 
LIBCOM_API int testOk (int pass, const char *fmt,...) EPICS_PRINTF_STYLE(2
 Test result with printf-style description. More...
 
LIBCOM_API int testOkV (int pass, const char *fmt, va_list pvar)
 Test result with var-args description. More...
 
LIBCOM_API void testPass (const char *fmt,...) EPICS_PRINTF_STYLE(1
 Passing test result with printf-style description. More...
 
LIBCOM_API void LIBCOM_API void testFail (const char *fmt,...) EPICS_PRINTF_STYLE(1
 Failing test result with printf-style description. More...
 

Test Harness for Embedded OSs

These routines are used to create a test-harness that can run multiple test programs, collect their names and results, then display a summary at the end of testing.

#define runTest(func)   runTestFunc(#func, func)
 Run a test program. More...
 
#define testHarnessDone()   testHarnessExit(0)
 Declare all test programs finished.
 
typedef int(* TESTFUNC )(void)
 
LIBCOM_API void testHarness (void)
 Initialize test harness.
 
LIBCOM_API void testHarnessExit (void *dummy)
 End of testing.
 
LIBCOM_API void runTestFunc (const char *name, TESTFUNC func)
 Run a single test program. More...
 

Detailed Description

Author
Andrew Johnson

The unit test routines make it easy for a test program to generate output that is compatible with the Test Anything Protocol and can thus be used with Perl's automated Test::Harness as well as generating human-readable output. The routines detect whether they are being run automatically and print a summary of the results at the end if not.

A test program starts with a call to testPlan(), announcing how many tests are to be conducted. If this number is not known a value of zero can be used during development, but it is recommended that the correct value be substituted after the test program has been completed.

Individual test results are reported using any of testOk(), testOk1(), testOkV(), testPass() or testFail(). The testOk() call takes and also returns a logical pass/fail result (zero means failure, any other value is success) and a printf-like format string and arguments which describe the test. The convenience macro testOk1() is provided which stringifies its single condition argument, reducing the effort needed when writing test programs. The individual testPass() and testFail() routines can be used when the test program takes a different path on success than on failure, but one or other must always be called for any particular test. The testOkV() routine is a varargs form of testOk() included for internal purposes which may prove useful in some cases.

If some program condition or failure makes it impossible to run some tests, the testSkip() routine can be used to indicate how many tests are being omitted from the run, thus keeping the test counts correct; the constant string why is displayed as an explanation to the user (this string is not printf-like).

If some tests are expected to fail because functionality in the module under test has not yet been fully implemented, these tests may still be executed, wrapped between calls to testTodoBegin() and testTodoEnd(). testTodoBegin() takes a constant string indicating why these tests are not expected to succeed. This modifies the counting of the results so the wrapped tests will not be recorded as failures.

Additional information can be supplied using the testDiag() routine, which displays the relevant information as a comment in the result output. None of the printable strings passed to any testXxx() routine should contain a newline '\n' character, newlines will be added by the test routines as part of the Test Anything Protocol. For multiple lines of diagnostic output, call testDiag() as many times as necessary.

If at any time the test program is unable to continue for some catastrophic reason, calling testAbort() with an appropriate message will ensure that the test harness understands this. testAbort() does not return, but calls the ANSI C routine abort() to cause the program to stop immediately.

After all of the tests have been completed, the return value from testDone() can be used as the return status code from the program's main() routine.

On vxWorks and RTEMS, an alternative test harness can be used to run a series of tests in order and summarize the results from them all at the end just like the Perl harness does. The routine testHarness() is called once at the beginning of the test harness program. Each test program is run by passing its main routine name to the runTest() macro which expands into a call to the runTestFunc() routine. The last test program or the harness program itself must finish by calling testHarnessDone() which triggers the summary mechanism to generate its result outputs (from an epicsAtExit() callback routine).

IOC Testing

Some tests require the context of an IOC to be run. This conflicts with the idea of running multiple tests within a test harness, as iocInit() is only allowed to be called once, and some parts of the full IOC (e.g. the rsrv CA server) can not be shut down cleanly. The function iocBuildIsolated() allows to start an IOC without its Channel Access parts, so that it can be shutdown quite cleanly using iocShutdown(). This feature is only intended to be used from test programs, do not use it on production IOCs. After building the IOC using iocBuildIsolated() or iocBuild(), it has to be started by calling iocRun(). The suggested call sequence in a test program that needs to run the IOC without Channel Access is:

#include "iocInit.h"
MAIN(iocTest)
{
testdbReadDatabase("<dbdname>.dbd", 0, 0);
<dbdname>_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("some.db", 0, 0);
... test code before iocInit(). eg. dbGetString() ...
... test code with IOC running. eg. dbGet()
return testDone();
}

The part from iocBuildIsolated() to iocShutdown() can be repeated to execute multiple tests within one executable or harness.

To make it easier to create a single test program that can be built for both the embedded and workstation operating system harnesses, the header file testMain.h provides a convenience macro MAIN() that adjusts the name of the test program according to the platform it is running on: main() on workstations and a regular function name on embedded systems.

Example

The following is a simple example of a test program using the epicsUnitTest routines:

#include <math.h>
#include "epicsUnitTest.h"
#include "testMain.h"
MAIN(mathTest)
{
testOk(sin(0.0) == 0.0, "Sine starts");
testOk(cos(0.0) == 1.0, "Cosine continues");
if (!testOk1(M_PI == 4.0*atan(1.0)))
testDiag("4 * atan(1) = %g", 4.0 * atan(1.0));
return testDone();
}

The output from running the above program looks like this:

1..3
ok 1 - Sine starts
ok 2 - Cosine continues
ok 3 - M_PI == 4.0*atan(1.0)
Results
=======
Tests: 3
Passed: 3 = 100%

Definition in file epicsUnitTest.h.

Macro Definition Documentation

#define testOk1 (   cond)    testOk(cond, "%s", #cond)
Parameters
condExpression to be evaluated and displayed.
Returns
The value of cond.

Definition at line 183 of file epicsUnitTest.h.

#define runTest (   func)    runTestFunc(#func, func)
Parameters
funcName of the test program.

Definition at line 276 of file epicsUnitTest.h.

Function Documentation

LIBCOM_API void testPlan ( int  tests)
Parameters
testsNumber of tests to be run. May be zero if not known but the test harness then can't tell if the program dies prematurely.
LIBCOM_API int testOk ( int  pass,
const char *  fmt,
  ... 
)
Parameters
passTrue/False value indicating result.
fmtA printf-style format string describing the test.
...Any parameters required for the format string.
Returns
The value of pass.
LIBCOM_API int testOkV ( int  pass,
const char *  fmt,
va_list  pvar 
)
Parameters
passTrue/False value indicating result.
fmtA printf-style format string describing the test.
pvarA var-args pointer to any parameters for the format string.
Returns
The value of pass.
LIBCOM_API void testPass ( const char *  fmt,
  ... 
)
Parameters
fmtA printf-style format string describing the test.
...Any parameters required for the format string.
Returns
The value of pass.
LIBCOM_API void LIBCOM_API void testFail ( const char *  fmt,
  ... 
)
Parameters
fmtA printf-style format string describing the test.
...Any parameters required for the format string.
LIBCOM_API void testSkip ( int  skip,
const char *  why 
)
Parameters
skipHow many tests are being skipped.
whyReason for skipping these tests.
LIBCOM_API void testTodoBegin ( const char *  why)
Parameters
whyReason for expected failures.
LIBCOM_API void testAbort ( const char *  fmt,
  ... 
)
Parameters
fmtA printf-style format string giving the reason for stopping.
...Any parameters required for the format string.
LIBCOM_API void LIBCOM_API int testDiag ( const char *  fmt,
  ... 
)
Parameters
fmtA printf-style format string containing diagnostic information.
...Any parameters required for the format string.
LIBCOM_API int testImpreciseTiming ( void  )

May be used to testSkip(), or select longer timeouts, for some cases when the test process may be preempted for arbitrarily long times. This is common in shared CI environments.

The environment variable $EPICS_TEST_IMPRECISE_TIMING=YES should be set in by such testing environments.

LIBCOM_API void runTestFunc ( const char *  name,
TESTFUNC  func 
)
Parameters
nameProgram name
funcFunction implementing test program