/CppUMockGen

Mock generator for CppUTest/CppUMock

Primary LanguageC++BSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

CppUMockGen

Mock generator for CppUTest/CppUMock.

Build status codecov

What is CppUMockGen?

CppUMockGen generates automatically mocks for member and non-member functions defined in C/C++ header files to avoid the burden of having to write these mocks manually when writing units tests using the CppUTest/CppUMock unit testing framework.

CppUMockGen additionally generates automatically expectation functions to improve and ease the declaration of expectations for functions in tests, making expectation declarations shorter and less error prone.

Why using CppUMockGen?

In real world projects with many components (e.g. classes) which interfaces often change, there will be many mocked functions and unit tests that have to be created and maintained.

CppUTest/CppUMock provides a very powerful mechanism to define mocks for C/C++ functions using MockSupport::actualCall and to declare function call expectations in unit tests using MockSupport::expectOneCall / MockSupport::expectNCalls.

However, defining and maintaining these mock definitions is a cumbersome, tedious and error prone task: the user has to ensure that the C/C++ signature of the mocking function is in sync with the function declaration (at least the compiler will moan if not), keep the symbolic ("stringified") name of the function in sync with the actual C/C++ name, declare each parameter individually and keep the parameter's symbolic names and data type usage in sync with the function parameters declarations, etc. Additionally, the expected call declarations have also to be maintained, keeping the symbolic names of the functions and parameters in sync with the ones used in mock definitions, etc.

The previously described manual tasks are highly systematic, and can be automated using CppUMockGen: this tool can generate automatically mock definitions for functions declared in C/C++ header files, and also their corresponding expectation functions that encapsulate the expectation cumbersome details.

Example

Assume that we have the following function that we want to test:

FunctionToTest.h

bool FunctionToTest( char *p );

And that this function calls another function, that we need to mock:

FunctionToMock.h

const char* FunctionToMock( const char *p1, int p2 );

With CppUMockGen we can generate the following mock:

FunctionToMock_mock.cpp

const char * FunctionToMock(const char * p1, int p2)
{
    return mock().actualCall("FunctionToMock")
        .withStringParameter("p1", p1)
        .withIntParameter("p2", p2)
        .returnStringValue();
}

Additionally, with CppUMockGen we can generate the following expectation:

FunctionToMock_expect.h

namespace expect {
MockExpectedCall& FunctionToMock(CppUMockGen::Parameter<const char *> p1,
                                 CppUMockGen::Parameter<int> p2,
                                 const char * __return__);
MockExpectedCall& FunctionToMock(unsigned int __numCalls__,
                                 CppUMockGen::Parameter<const char *> p1,
                                 CppUMockGen::Parameter<int> p2,
                                 const char * __return__);
}

Eventually, we can use these generated mocks and expectations in an unit test like the following example, which checks that the tested function calls the mocked function once, with the string "ABC" passed as the first parameter, ignoring the value of the second parameter, then gets the string "123" as the result of the call, and finally returns true:

FunctionToTest_test.cpp

using CppUMockGen::IgnoreParameter;

TEST( TestSuite, FunctionToTest )
{
    // Prepare
    expect::FunctionToMock( "ABC",                 // Parameter p1
                            IgnoreParameter::YES,  // Parameter p2
                            "123" );               // Return value

    // Exercise
    bool ret = FunctionToTest( "ABC" );

    // Verify
    CHECK_EQUAL( true, ret );
    mock().checkExpectations();
}

Download Binaries

The last releases for Windows and Linux can be found in GitHub Releases in different formats:

  • Installer for Windows (x64).
  • Portable package for Windows (x64).
  • Debian package for Linux (x64), tested on Ubuntu 18.04 LTS.
  • Portable package for Linux (x64)

On Ubuntu systems you can install CppUMockGen from the CppUMockGen PPA repository.

Getting Started

Basic Command-Line Options

CppUMockGen [OPTION...] [<input>]

OPTION Description
-i, --input <input> Input file path
-m, --mock-output <mock-output> Mock output directory or file path
-e, --expect-output <expect-output> Expectation output directory or file path
-x, --cpp Force interpretation of the input file as C++
-s, --std Set language standard (c++14, c++17, etc.)
-I, --include-path <path> Include path
-B, --base-directory <path> Base directory path
-t, --type-override <expr> Override generic type
-f, --config-file <file> Configuration file to be parsed for options
-v, --version Print version
-h, --help Print help

To generate a mock from a header file containing the functions that you want to mock, just pass the path to the header file as input in the first non-option argument or explicitly with the -i / --input option, and the path where you want the file with the mocked functions to be generated as output using the -m / --mock-output option.

To generate expectations, pass the path where you want the files with the expectation to be generated as output using the -e / --expect-output option (additionally to or instead of the -m option).

CppUMockGen, just as any C/C++ compiler, needs to know where to find other include files referenced by the input file in order to interpret it properly. Pass the paths to the necessary include directories by using the -I / --include-path option. Like with most compilers, you may use this option several times to indicate multiple include directories.

Mocks and expectations generated by CppUMockGen need to include the mocked header file. By default, the mocked header file will be referenced with a relative path from the directory where the mocks/expectations are generated. This behavior may be overriden using the -B / --base-directory option to set a base directory to reference included mocked headers (e.g., set it to a directory that is in the include path when compiling tests).

CppUMockGen deduces the data types to use with CppUMock from the actual function parameters and return types. If the API that you are mocking is well designed (e.g. pointers to non-const values are not used for input parameters), CppUMockGen will guess properly in most cases the correct types. Nevertheless, mocked data types can be overridden by using -t / --type-override options to indicate the type of function parameters or function returns. Type overriding can be defined in generic form, which apply to any function parameter or return types that match the specified type, or can be defined in function-specific form, which apply to parameters and return types of the specified function.

Since complex mocks will require a lot of override options, and many of them can be reused to generate mocks for other files, you can store options in a text file and load that file using the -f / --config-file option.

Usage Manual

You can find complete information on the usage of CppUMockGen in the CppUMockGen Usage Manual.

Building from Source

Requirements

Build using MinGW (Windows)

To build CppUMockGen first clone this repository on your machine, and in the directory where you cloned it (top directory) execute the following commands:

mkdir build_mingw
cd build_mingw
cmake .. -G "MinGW Makefiles"
mingw32-make

To execute the tests execute the following command in the build_mingw directory:

mingw32-make run_tests

If the Coverage build type is selected, to generate the coverage report execute the following command in the build_mingw directory:

mingw32-make coverage_report

The coverage report will be generated in the coverage_lcov directory under the top directory.

Build using Visual Studio (Windows)

To build CppUMockGen first clone this repository on your machine, and in the directory where you cloned it (top directory) execute the following commands (where <Visual Studio XX 20YY> is a cmake generator for visual studio, e.g., "Visual Studio 16 2019", "Visual Studio 17 2022"):

mkdir build_vs
cd build_vs
cmake .. -G "<Visual Studio XX 20YY>"

Eventually open the CppUMockGen.Top.sln VS solution generated in the build_vs directory, then compile the solution.

To execute the tests, compile the run_tests project.

If coverage is enabled, to generate the coverage report compile the run_coverage project, and the report will be generated in the coverage_msvc directory under the top directory.

Build using GCC (Linux)

To build CppUMockGen first clone this repository on your machine, and in the directory where you cloned it (top directory) execute the following commands:

mkdir build_gcc
cd build_gcc
cmake ..
make

To execute the tests execute the following command in the build_gcc directory:

make run_tests

If the Coverage build type is selected, to generate the coverage report execute the following command in the build_gcc directory:

make coverage_report

The coverage report will be generated in the coverage_lcov directory under the top directory.

Build Options

Build Types

The following build types are supported:

  • Release
  • Debug
  • RelWithDebInfo (Release build with debug information)
  • MinSizeRel (Release with executable size minimization)
  • Coverage (Only GCC/MinGW)

When using Visual Studio, the available build types are available as project configurations. Coverage is enabled by default, to disable it pass the option -DCOVERAGE=OFF to CMake.

When using GCC/MinGW, the default build type is Release. To select a different build type pass the option -DCMAKE_BUILD_TYPE=<Build Type> to CMake.

Finding Dependencies

If during configuration CMake cannot find some dependencies, their installation paths can be indicated by passing one of the following options to CMake:

  • libClang: -DLibClang_HOME=<Path to LLVM top directory>
  • CppUTest: -DCppUTest_HOME=<Path to CppUTest top directory>
  • LCOV: -Dlcov_HOME=<Path to LCOV top directory>