Test Point Testing in C/C++
Testpoints provide an easy-to-use framework for solving a class of common yet difficult unit testing problems:
How can I observe and verify activity that occurs in another thread?
A couple of common scenarios that become a lot more testable via testpoints include:
- Verification of State machine operation
- Verification of communication drivers
Instrumenting Target Threads
Target threads are instrumented by placing a line of the following form into the source code:
...
srTEST_POINT("testpoint name");
...
When this code is executed it broadcasts a message via the STRIDE runtime which is detected by the test (IM) thread if it is currently looking for testpoints (i.e. in a srTEST_POINT_WAIT()). We refer to this as a "testpoint hit".
Instrumenting the Test Thread
The test thread is instrumented using these steps:
- Specify an expectation set (i.e. the testpoints that are expected to be hit)
- Register the expectation set with the STRIDE runtime
- Wait for the expectation set to be satisfied or a timeout to occur
Specifying the Expectation Set
An expectation set is an array of srTestPointExpect_t structures. srTestPointExpect_t is typdef'd as follows:
typedef struct
{
/* the label value is considered the testpoint's identity */
const srCHAR * label;
/* count specifies the number of times the testpoint is expected to be hit */
srDWORD count;
/* data specifies an optional string data payload */
const srCHAR * data;
} srTestPointExpect_t;
Basic Example
A typical delcaration of an expectation set looks like this:
srTestPointExpect_t expected[]= {
{"START"},
{"ACTIVE"},
{"IDLE"},
{"END"},
{0}};
This example specifies the expectation of one hit each of the testpoints "START", "ACTIVE", "IDLE", and "END".
A few things to note:
- The end of the array is marked by a srTestPointExpect_t set to all zero values
- Structure members we omit in the array declaration are set to 0 by the compiler
- A count value of either 0 or 1 is interpreted as 1
- A data value 0 indicates that there is no payload data associated with this testpoint
Registering the Expectation Set
To register an expectation set, we call srTestPointExpect and receive a handle to identify the expectation set in the next step.
The registration looks like this:
srWORD handle;
srTestPointExpect(expected, &handle);
Waiting for the Expectation Set to be Satisfied
The final step is to wait for the expectation to be satisfied. We do this using the srTEST_POINT_WAIT() macro as shown below.
srTEST_POINT_WAIT(handle, expect_flags, timeout);
The macro takes three arguments
Expect Flags
Argument | Description |
handle | The handle returned from the call to srTestPointExpect() used to register the expectation set |
expect_flags | Value that customizes the expectation in terms of testpoint hit order and testpoint exclusivity |
timeout | Timeout value in milliseconds; 0 means infinite timeout |
Expect Flags | Unexpected Testpoint causes test failure |
Out of order Testpoint causes failure |
0 | ||
srTEST_POINT_WAIT_ORDER | X | |
srTEST_POINT_WAIT_STRICT | X | |
srTEST_POINT_WAIT_ORDER | srTEST_POINT_WAIT_STRICT | X | X |