CMock Documentation

repository·master·Indexed 21 days ago

https://github.com/throwtheswitch/cmock

A mock and stub generator for C unit testing that automates the creation of mock interfaces by parsing C header files. Part of the ThrowTheSwitch.org ecosystem, CMock integrates with Unity Test and can be managed via the Ceedling build manager. It provides features for argument validation, return value control, call order verification, and support for custom assertions, callbacks, and stubs.

Tokens
13K
Snippets
28
Records
60
Agent score
74%

What's inside CMock

  1. Overview of CMock

    master

    CMock is a mock and stub generator and runtime designed for unit testing C code. It automatically parses C header files to create mock interfaces. It is designed to integrate seamlessly with Unity Test, another testing tool from ThrowTheSwitch.org.

    For users who prefer not to manage unit testing builds manually, Ceedling is recommended as a test-centered build manager that integrates with CMock.

  2. What is CMock and how does it work?

    master

    CMock is a tool that takes C header files and automatically generates a Mock interface for them. This allows you to replace real function implementations with mocked versions during unit testing.

    With these mocks, you can:

    1. Verify arguments: Ensure the function under test passes the correct data to its dependencies.
    2. Control return values: Force the mock to return specific data or errors.
    3. Simulate behavior: Make the mock throw exceptions or execute callbacks.
    4. Verify call order and frequency: Ensure functions are called the expected number of times and in the correct sequence.

    CMock is built on top of Unity and uses Ruby (version 3.0.0 or higher) for its core logic.

  3. Naming conventions and philosophy

    master

    The project follows a specific hierarchy for naming to ensure code is easy to maintain. When choosing names for files, functions, or variables, prioritize them in this order:

    1. Readable: Avoid double negatives and cryptic abbreviations. Use natural flow.
    2. Descriptive: Prefer longer, descriptive names over short, ambiguous ones.
      • Exception: Avoid Hungarian notation (encoding type info in names).
      • Exception: Use i, j, and k for simple loop counters or throw-away local variables.
    3. Consistent: Follow established patterns (e.g., using UNITY_EXCLUDE_BLAH or UNITY_USES_BLAH for configuration macros).
    4. Memorable: Use unique, descriptive names that are easy to search for (e.g., release_invoker instead of a generic name).
  4. Use callbacks and stubs in mocks

    master

    When standard Expect functions are insufficient, you can use callbacks or stubs to implement custom logic. CMock provides two primary ways to do this, which reset the function's call count to zero:

    1. func_AddCallback: The mock performs normal argument and calling order checks (based on your Expect setup) before executing the callback.
    2. func_Stub: The mock skips all normal checks and jumps directly to your custom callback, effectively replacing the mock's default behavior.

    The callback signature depends on the original function's signature:

    • void func(void) $\rightarrow$ void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback) where CMOCK_func_CALLBACK is void func(int NumCalls)
    • void func(params) $\rightarrow$ void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback) where CMOCK_func_CALLBACK is void func(params, int NumCalls)
    • retval func(void) $\rightarrow$ void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback) where CMOCK_func_CALLBACK is retval func(int NumCalls)
    • retval func(params) $\rightarrow$ void func_[AddCallback,Stub](CMOCK_func_CALLBACK callback) where CMOCK_func_CALLBACK is retval func(params, int NumCalls)

    NumCalls represents the number of calls made since the current stub or callback was installed. You can also query the current call count at any time using func_CallCount().

    // Example: Using a callback to return a specific value via a pointer
    // Assuming: uint divide(uint n, uint d, uint *result);
    
    uint result_1 = 42;
    divide_ExpectAndReturn(5, 2, NULL, TRUE);
    divide_IgnoreArg_result();
    divide_ReturnThruPtr_result(&result_1);
  5. Mocking C++ static member methods

    master

    CMock is designed to mock C functions and C++ static member methods. It does not mock non-static (instance) members; for those, you should use a dedicated C++ mocking framework.

    Handling Multiple Definitions

    When mixing CMock with a C++ framework, you may encounter multiple definition errors because the C++ framework might link the real object. To resolve this, use the weak attribute in your real implementation for any functions that CMock mocks:

    #if defined(TEST)
            __attribute__((weak))
    #endif

    Generated Function Naming

    To avoid collisions with namespaces or classes, CMock generates function names by including the namespace and class hierarchy.

    Example Mapping: If you have:

    namespace MyNamespace {
        class MyClass {
            static int DoesSomething(int a, int b);
        };
    }

    CMock will generate: void MyNamespace_MyClass_DoesSomething_ExpectAndReturn(int a, int b, int toReturn);

    namespace MyNamespace {
        class MyClass {
            static int DoesSomething(int a, int b);
        };
    }
    
    // Generates:
    // void MyNamespace_MyClass_DoesSomething_ExpectAndReturn(int a, int b, int toReturn);
  6. Use CMock plugins

    master

    CMock supports various plugins to extend its mocking capabilities:

    • Array Plugin: Enables byte-by-byte comparison for void* and provides _ExpectWithArray / _ExpectWithArrayExtended for array-based argument verification.
    • Stateless Ignore Plugin: (Added in 2.5.3) Provides a way to ignore calls without maintaining state.
    • ExpectAnyArgs Plugin: (Added in 2.5.0) Generates functionality to ignore all arguments in a function call.
    • Ignore Plugin: Includes functions like StopIgnore (added in 2.5.1) to control the ignoring of calls.
  7. Handle arrays and pointers in mocks

    master

    As of CMock 2.7.0, array and pointer handling has been significantly improved:

    • Multidimensional Arrays: Arrays (including multidimensional ones) are now passed as arrays.
    • String vs. Byte Array: The Array plugin allows you to treat char* (string) arguments as byte arrays using _ExpectWithArray, while still allowing them to be treated as strings via _Expect.
    • Automatic Pointer/Length Pairing: CMock now automatically detects pointer/length argument pairs. When a pointer is auto-paired with a size argument, _ExpectWithArrayExtended is generated as a fallback to allow you to explicitly override the depth.
    • void* Comparison:
      • Without the array plugin: void* defaults to pointer comparison.
      • With the array plugin: void* defaults to byte-by-byte comparison.
    • Complex Types: Improved handling for arrays of pointers, pointers to arrays, and function-looking structs or macros.
    // Example of the improved array/pointer capabilities (conceptual)
    // Using _ExpectWithArray for byte-wise comparison of a string
    _ExpectWithArray(my_function, my_string_ptr, length);
    
    // Using _Expect for standard string comparison
    _Expect(my_function, my_string_ptr);
  8. Use emojis in commit messages and issues

    master

    To improve clarity and visual organization, use the following emojis in commit messages, Issues, and Feature Requests:

    Actions

    • :seedling: (or :cactus:, :herb:, :evergreen_tree:, :palm_tree:, :deciduous_tree:, :blossom:): Growing new features
    • :art:: Improving code format/structure
    • :racehorse:: Improving performance
    • :non-potable_water:: Plugging memory leaks
    • :memo:: Writing documentation
    • :bug: (or :beetle:, :ant:, :honeybee:): Fixing a bug
    • :fire:: Removing code or files
    • :green_heart:: Fixing the CI build
    • :white_check_mark:: Adding tests
    • :lock:: Dealing with security
    • :arrow_up:: Upgrading dependencies
    • :arrow_down:: Downgrading dependencies
    • :shirt:: Removing linter warnings

    Platforms

    • :penguin:: Fixing something on Linux
    • :apple:: Fixing something on macOS
    • :checkered_flag:: Fixing something on Windows
  9. Install CMock

    master

    CMock can be installed using several methods depending on your build environment:

    1. Using Ceedling: If you are using the Ceedling build manager, CMock is handled automatically; no manual installation is required.
    2. GitHub Clone (Recommended): Clone the repository recursively to ensure all submodules are included.
    3. GitHub Zip: You can download the zip file, but you must manually download and include the dependencies Unity and CException, as they are not included in the zip archive.
    git clone --recursive https://github.com/throwtheswitch/cmock.git
  10. Follow coding style and linting guidelines

    master

    Consistency with the existing codebase is required. When modifying files, follow the established style, formatting, and naming conventions (e.g., if private properties use an underscore prefix _, continue using that pattern; if methods use camelCase, do not switch to snake_case).

    Linting is enforced for the following languages:

  11. Use resetTest to validate expectations iteratively

    master

    If you are using Unity's test runner generator scripts or Ceedling, a resetTest function is generated in your runner.

    Calling resetTest() during a test will:

    1. Validate all CMock expectations up to that point.
    2. Reset the CMock state to start fresh.

    This is useful for testing a single function multiple times with different arguments within the same test case.