This topic explains how to add user-defined stubs to replace calls to resources that you cannot (or do not want to) access during testing, as well as how to modify automatically-generated stubs. See Stubs for background information about stubs and how they help you test software during the development.
Sections include:
|
The Stubs view provides details on the stub configuration based on the most recent run of a unit testing Test Configuration. It allows you to modify the configuration by adding user-defined stubs or automatically generating stubs for missing symbols.
Choose Parasoft> Show View> Stubs to access the Stubs view.
The Stubs view will be empty except for a message stating "Symbols data not collected" when you open it for the first time. |
The Stubs view contains a table with the following columns:
The content in the Stubs view is updated based on data collected during unit testing and in response to specific actions available from the Stubs view (i.e., Create User Stub, Generate Auto Stub). Note that contents won't be updated in response to external actions that you perform, such as manually adding/removing stubs, etc.
The Stubs view presents information about the most-recently used stub configuration, as well as other available (but not used) definitions. For instance, it shows information about the existing original definitions for functions that have user-defined stubs. For these types of definitions, (not used)
is displayed in the 'Definition' column, for example: Original (not used)
. To hide such definitions in the Stubs view, click Filter in the Stubs view tool bar and enable the Hide unused definitions option.
If a single function has more than one stub definition (for example, if there are two user stub definitions for a particular function), then the Stubs view will show both stubs. An error mark will appear on the stub icon and display (conflict
) in the 'Definition' column, for example: User
(conflict
).
To collect or refresh symbols data:
The Stubs view allows you to specify the location where auto-generated stubs will be saved, as well as enable or disable a desired mode of dynamic stub configuration (see Dynamic Stubs Configuration):
To add user-defined stubs by creating and editing a wizard-generated stub file:
The stubs directory can be located anywhere within the project. By default, C/C++test expects stubs to be stored in a subdirectory of the project’s stubs directory. However, you can use a different location as long as you modify the Test Configuration’s Use extra symbols from files found in setting (in the Execution> Symbols tab) accordingly.
If you do not want to store your stubs within the project directory, you can add a folder that links to files stored elsewhere in your file system. To do this: a. Choose File> New> Folder (if this is not available, choose File> New> Other, select General> Folder, then click Next). b. Click the Advanced button. c. Enable the Link to folder in file system option. d. Enter or browse to the location of your source files. e. Click Finish. |
Select your stubs directory in the project tree and right-click the selection, then choose New> Other from the shortcut menu. A wizard will open. Select C++test> User stub, then click Next.In that wizard’s functions table, select the function for which you want to create a stub and click Next.
|
#include
directives.#include
directives as needed.To quickly add stubs for all functions from a given library, sort the table by Location so it is easier to select all functions from that library. |
To add user-defined stubs to an empty stub file:
Select your stubs directory in the project tree,right-click the selection, then choose New> Other from the shortcut menu. A wizard will open. Select C++test> User stub, then click Next. Then, in that wizard’s functions table, select the function for which you want to create a stub, and click Next.
Create a stub template by typing stub, placing your cursor immediately after the "b" in "stub", pressing Ctrl+ Space, then choosing the appropriate template (either a standard stub template for a C or C++ function, or a constructor/destructor stub template).
You can use the Tab key to move between ret_type, scope, name, and parameters. |
8. Enter the stub body/definition. Noe that user-defined stubs can interact with C/C++test API functions as described in C++test API Functions for User-Defined Stubs.
9. Save the modified file.
Be sure to set the Test Configuration’s Function stubs mode to Stub all calls as follows:
|
When stubbing virtual function calls, be sure to create a stub for a function from a class that the given pointer or reference points to at compilation time. For example, the call marked with (*) will be stubbed only if a stub for a Base::doSth() method is created in the following code:
The actual runtime type of the object pointed to by the pointer does not matter. |
To create user stubs for operators, use the following stub function names:
Operator | Function Name |
---|---|
new | CppTest_Stub_operator_new |
delete | CppTest_Stub_operator_delete |
new[] | CppTest_Stub_operator_array_new |
delete[] | CppTest_Stub_operator_array_delete |
+ | CppTest_Stub_operator_plus |
- | CppTest_Stub_operator_minus |
* | CppTest_Stub_operator_star |
/ | CppTest_Stub_operator_divide |
% | CppTest_Stub_operator_remainder |
^ | CppTest_Stub_operator_excl_or |
& | CppTest_Stub_operator_ampersand |
| | CppTest_Stub_operator_or |
~ | CppTest_Stub_operator_or |
! | CppTest_Stub_operator_not |
= | CppTest_Stub_operator_assign |
< | CppTest_Stub_operator_lt |
> | CppTest_Stub_operator_gt |
+= | CppTest_Stub_operator_plus_assign |
-= | CppTest_Stub_operator_minus_assign |
*= | CppTest_Stub_operator_times_assign |
/= | CppTest_Stub_operator_divide_assign |
%= | CppTest_Stub_operator_remainder_assign |
^= | CppTest_Stub_operator_excl_or_assign |
&= | CppTest_Stub_operator_and_assign |
|= | CppTest_Stub_operator_or_assign |
<< | CppTest_Stub_operator_shift_left |
>> | CppTest_Stub_operator_shift_right |
>>= | CppTest_Stub_operator_shift_right_assign |
<<= | CppTest_Stub_operator_shift_left_assign |
== | CppTest_Stub_operator_eq |
!= | CppTest_Stub_operator_ne |
<= | CppTest_Stub_operator_le |
>= | CppTest_Stub_operator_ge |
&& | CppTest_Stub_operator_and_and |
|| | CppTest_Stub_operator_or_or |
++ | CppTest_Stub_operator_plus_plus |
-- | CppTest_Stub_operator_minus_minus |
->* | CppTest_Stub_operator_arrow_star |
-> | CppTest_Stub_operator_arrow |
() | CppTest_Stub_operator_function_call |
[] | CppTest_Stub_operator_subscript |
<? | CppTest_Stub_operator_gnu_min |
>? | CppTest_Stub_operator_gnu_max |
, | CppTest_Stub_operator_comma |
Right-click the function in the table and choose Generate Auto Stub from the shortcut menu to generate an Auto Stub file for a symbol with missing definitions. An Auto Stub file will be created and opened in the editor. C/C++test will automatically add the appropriate definition and required #include directives.
You can also create Auto Stubs for multiple symbols at the same time:
You can also create Auto Stubs for symbols without available definitions. For other symbols, use User Stubs instead.
Auto Stubs have the lowest priority. An Auto Stub will not be used if any other definition is available.
C/C++test can be used to automatically generate customizable stubs for missing function and variable definitions as described above.
Automatically-generated stubs have the same functionality as user-defined stubs, but are marked with the CppTest_Auto_Stub_
prefix (instead of the CppTest_Stub_
prefix). This allows you to have multiple stubs for the same function the in scope.
If C/C++test cannot automatically generate a complete stub definition, it will create a stub template that you can customize (by entering the appropriate return statement, adding include directives etc.). Stub templates will be saved in the stub file before complete stubs.
Automatically generated stubs will be used only if no other definition (user stub or original) is available.
You can readily configure automatically-generated stubs either through the dynamic stubs configuration API (see Dynamic Stubs Configuration) or by using the Test Case Editor Stubs step (see Working with Steps).
In rare cases where the dynamic stubs configuration API or Test Case Editor is insufficient, you can completely replace the body of generated stubs with a custom logic implementation, such as the CppTest_IsCurrentTestCase
stub function (see “C/C++test API Functions for User-Defined Stubs C++test API Functions for User-Defined Stubs).
To customize these stubs or stub templates:
Note that C++test’s stubs (except for constructor stubs) take the same values as the original functions.
Safe definitions are automatically-generated to replace "dangerous" functions. Safe definitions are available for most system I/O routines (rmdir()
, remove()
, rename()
, etc.). If a safe definition is used, the originals are not called—even if they are available. We recommend that you use safe definitions when they are available; using these definitions prevents problems during unit testing. These stubs cannot be modified.
If you do not want to use the automatically-generated safe definitions, delete the ${cpptest:cfg_dir}/safestubs
entry from the Use extra symbols from files found in field in the Test Configuration’s Execution> Symbols tab.
If you want to disable usage of a safe stub for a particular function (and use the original definition instead), write the user stub that will work as a wrapper for the original function call. For example:
int CppTest_Stub_mkdir(const char* p) { return mkdir(p); } |
void CppTest_Assert(bool test, const char * message) |
This function works in a similar fashion to a standard assert function. Whenever the value of the "test" parameter is false, test case execution is stopped. A "User-defined assertion failed" message will be reported as the test case result. In addition, the value of the "message" parameter will be shown as a detailed failure description, along with location and stack trace details.
void CppTest_Break() |
This function allows you to unconditionally stop the test case execution. Test cases stopped in this manner result in a "User-defined break called" message. In addition, the location and stack trace information is available.
bool CppTest_IsCurrentTestCase(const char* id; |
This function allows you to query the currently executed test case. It will return true
if the specified id equals the name of the currently executed test case, otherwise it will return false
. This feature is useful for functions that use conditional statements based on the external function calls. See Functions for Stubs Driven by Test Cases for an example.
bool CPPTEST_DS_HAS_COLUMN(const char* name) |
This function allows you to query data source columns in user/auto stubs. Note that data sources are test case specific, so the data is available only when the stub is called in the context of a given test case (it is not available when the stub is called during global initialization, etc).
const char* CppTest_GetCurrentTestCaseName(); const char* CppTest_GetCurrentTestSuiteName(); |
These functions get the name of the currently-executed test case and test suite. Using these functions, you can write a stub that applies to a specific test case from a specific test suite.
See Functions for Stubs Driven by Test Cases for an example.
Any data source that you configure for use in C/C++test can be used in stubs.
To configure a data source, use the instructions provided in Adding Data Sources.
To use a data source in a stub, use the bool CPPTEST_DS_HAS_COLUMN(const char* name) API function. You can query a data source column in a stub as follows:
int CppTest_Stub_goo (void) { if (CPPTEST_DS_HAS_COLUMN("stub_goo_return")) { return CPPTEST_DS_GET_INTEGER("stub_goo_return"); } else { return 0; // Data Source not available } } |
Note that data sources are test case specific, so the data is available only when the stub is called in the context of a given test case (it is not available when the stub is called during global initialization etc).
The bool CPPTEST_DS_HAS_COLUMN(const char* name)
macro can also be combined with other API functions—such as CppTest_isCurrentTestCase().
See Using Different Tests and/or Stubs for Different Contexts.
See Dynamic Stubs Configuration.
C/C++test allows you to create stubs that can be "driven" by the currently executed test case. The C/C++test API provides the following function:
bool CppTest_IsCurrentTestCase(const char* id); |
This function can be used in the "user stub" definition to query a currently executed test case. It will return true
if specified id equals the name of the currently executed test case, otherwise it will return false
.
This feature is useful for functions that use conditional statements based on the external function calls. For example:
void foo() { if (goo() == 1) { //code } else { //code } } |
To achieve 100% line coverage, you could create two test cases for the foo()
function and then create a user stub for the goo()
function:
int ::CppTest_Stub_goo() { if (CppTest_IsCurrentTestCase("TestCase1")) { return 1; } else { return 0; } } |
This stub is now "driven" by test cases. In this example, the return value depends on the currently executed test case: it depends upon the TestCase1
test case. For TestCase1
, it will return 1, and for any other test case(s) it will return 0. In this way, you could achieve 100% coverage for the foo()
function.
Other API functions that are useful for writing stubs driven by test cases are const char* CppTest_GetCurrentTestCaseName()
; and const char* CppTest_GetCurrentTestSuiteName();. These functions get the name of the currently-executed test case and test suite. Using these functions, you can write a stub that applies to a specific test case from a specific test suite. For example, the following stub behaves differently for all test cases that have a name containing "nomemory" and that are from the "AllocTestSuite" test suite:
#include <string> #include <stdlib.h> EXTERN_C_LINKAGE void* CppTest_Stub_malloc(size_t size) { std::string testSuiteName = CppTest_GetCurrentTestSuiteName(); std::string testCaseName = CppTest_GetCurrentTestCaseName(); if ((testSuiteName == "AllocTestSuite") && (testCaseName.find("nomemory") != std::string::npos)) { // Simulate no memory situation. return 0; } return malloc(size); } |
You can set custom compiler options (for instance, to use C/C++test-specific flags) for each user-defined stub file as described in Specifying Custom Compiler Settings and Linker Options.