Main Content

Incorrect use of mocking API

Mock function accessed outside test body, and so on

Since R2023b

Description

This defect occurs when you invoke the mock function selector PST_SELECT_MOCK outside a test body, for instance, in a test configuration.

This checker is enabled if you specify the value pstunit for the option Libraries used (-library) or find defects in a test file from the Polyspace Platform (Polyspace Test) user interface. For more information, see Check for Bugs and Run-Time Errors in C/C++ Tests and Functions Under Test (Polyspace Test).

Risk

All selected mock functions get reset before a test is run. If you select a mock outside a test body, the mock does not get used in the test.

Fix

Move the PST_SELECT_MOCK statement inside a test body, that is, inside a PST_TEST_BODY block.

Examples

expand all

In this example, in the source file, a function set() calls another function init() but during testing, the call to init() needs to be replaced with a call to a mock function. The mock functions init_mock_0() and init_mock_1() are defined in a separate file, and invoked during testing using the mock selector PST_SELECT_MOCK. However, the mock selector is invoked incorrectly in a test configuration instead of a test body. Specifically, the mock selector is invoked in setup functions such as setMock0() and setMock1() that are registered with PST_SETUP and called during test setup.

  • Source (to be compiled with the macro PSTEST_MODE defined):

    int aGlobal;
    
    void init_mocks(int num);
    void init(int num)
    {
        aGlobal = num;
    }
    
    void set(int num)
    {
    #ifndef PSTEST_MODE
        init(num);
    #else
        init_mocks(num);
    #endif
    }
    

  • Header for mocks (named mocks.h):

    #include <pstunit.h>
    #ifndef INIT_MOCK_VARIANT
    #define INIT_MOCK_VARIANT
    
    PST_MOCK_SELECTOR_EXTERN(init);
    
    enum pst_mock_selector_init_enum {
        PST_FCN_INIT_MOCK_VARIANT_DEFAULT = 0,
        mock_0,
        mock_1
    };
    
    #endif 

  • Mocks:

    #include "mocks.h"
    
    extern int aGlobal;
    
    PST_MOCK_SELECTOR(init);
    void init(int num);
    
    static void init_mock_0 (int num)
    {
        aGlobal = 0;
    }
    
    static void init_mock_1 (int num)
    {
        aGlobal = 1;
    }
    
    void init_mocks(int num)
    {
        switch (PST_SELECTED_MOCK(init))
            {
            case mock_0:
                init_mock_0(num);
                return;
            case mock_1:
                init_mock_1(num);
                return;
            default:
                init(num);
                return;
            }
    }

  • Tests:

    #include "mocks.h"
    
    extern int aGlobal;
    void set(int num);
    
    PST_SUITE_CONFIG(testsWithMocks) {}
    
    PST_TEST_CONFIG(testsWithMocks, testNoMock) {}
    PST_TEST_BODY(testsWithMocks, testNoMock) {
        int test_data = 10;
        set(test_data);
        PST_VERIFY_EQ_INT(aGlobal, 10);
    }
    
    void setMock0(void) {
        PST_SELECT_MOCK(init, mock_0);
    }
    
    PST_TEST_CONFIG(testsWithMocks, testMock0) {
        PST_SETUP(setMock0) ;
    }
    PST_TEST_BODY(testsWithMocks, testMock0) {
        int test_data = 10;
        set(test_data);
        PST_VERIFY_EQ_INT(aGlobal, 0);
    }
    
    
    void setMock1(void) {
        PST_SELECT_MOCK(init, mock_1);
    }
    
    PST_TEST_CONFIG(testsWithMocks, testMock1) {
         PST_SETUP(setMock1) ;
    }
    PST_TEST_BODY(testsWithMocks, testMock1) {
        int test_data = 10;
        set(test_data);
        PST_VERIFY_EQ_INT(aGlobal, 1);
    }
    
    PST_REGFCN(myRegFcn) {
        PST_ADD_TEST(testsWithMocks, testNoMock);
        PST_ADD_TEST(testsWithMocks, testMock0);
        PST_ADD_TEST(testsWithMocks, testMock1);
    }
    
    #ifndef PSTEST_BUILD
    int main(int argc, char *argv[]) {
        PST_REGFCN_CALL(myRegFcn);
        return PST_MAIN(argc, argv);
    }
    #endif

Correction — Select Mock in Test Body

Instead of test setup, invoke the mock selector macro PST_SELECT_MOCK directly in a test body. The corrected test file is shown below.

  • Source (to be compiled with the macro PSTEST_MODE defined):

    int aGlobal;
    
    void init_mocks(int num);
    void init(int num)
    {
        aGlobal = num;
    }
    
    void set(int num)
    {
    #ifndef PSTEST_MODE
        init(num);
    #else
        init_mocks(num);
    #endif
    }
    

  • Header for mocks (named mocks.h):

    #include <pstunit.h>
    #ifndef INIT_MOCK_VARIANT
    #define INIT_MOCK_VARIANT
    
    PST_MOCK_SELECTOR_EXTERN(init);
    
    enum pst_mock_selector_init_enum {
        PST_FCN_INIT_MOCK_VARIANT_DEFAULT = 0,
        mock_0,
        mock_1
    };
    
    #endif 

  • Mocks:

    #include "mocks.h"
    
    extern int aGlobal;
    
    PST_MOCK_SELECTOR(init);
    void init(int num);
    
    static void init_mock_0 (int num)
    {
        aGlobal = 0;
    }
    
    static void init_mock_1 (int num)
    {
        aGlobal = 1;
    }
    
    void init_mocks(int num)
    {
        switch (PST_SELECTED_MOCK(init))
            {
            case mock_0:
                init_mock_0(num);
                return;
            case mock_1:
                init_mock_1(num);
                return;
            default:
                init(num);
                return;
            }
    }

  • Tests:

    #include "mocks.h"
    
    extern int aGlobal;
    void set(int num);
    
    PST_SUITE_CONFIG(testsWithMocks) {}
    
    PST_TEST_CONFIG(testsWithMocks, testNoMock) {}
    PST_TEST_BODY(testsWithMocks, testNoMock) {
        int test_data = 10;
        set(test_data);
        PST_VERIFY_EQ_INT(aGlobal, 10);
    }
    
    
    PST_TEST_CONFIG(testsWithMocks, testMock0) {
    }
    PST_TEST_BODY(testsWithMocks, testMock0) {
        int test_data = 10;
        PST_SELECT_MOCK(init, mock_0);
        set(test_data);
        PST_VERIFY_EQ_INT(aGlobal, 0);
    }
    
    
    PST_TEST_BODY(testsWithMocks, testMock1) {
        int test_data = 10;
        PST_SELECT_MOCK(init, mock_1);
        set(test_data);
        PST_VERIFY_EQ_INT(aGlobal, 1);
    }
    
    PST_REGFCN(myRegFcn) {
        PST_ADD_TEST(testsWithMocks, testNoMock);
        PST_ADD_TEST(testsWithMocks, testMock0);
        PST_ADD_TEST(testsWithMocks, testMock1);
    }
    
    #ifndef PSTEST_BUILD
    int main(int argc, char *argv[]) {
        PST_REGFCN_CALL(myRegFcn);
        return PST_MAIN(argc, argv);
    }
    #endif

Result Information

Group: Libraries Misuse
Language: C | C++
Default: Off
Command-Line Syntax: PSTUNIT_MISUSE_MOCKING
Impact: Medium

Version History

Introduced in R2023b