CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/cmock-reference

Pure-reference catalog of CMock and Ceedling mocking semantics for C. Defines what CMock generates from a C header (the full Expect / ExpectAndReturn / ExpectAnyArgs / ExpectWithArray / Ignore / IgnoreAndReturn / IgnoreArg_{param} / ReturnThruPtr_{param} / AddCallback / Stub / ExpectAndThrow naming family), the cmock.yml :plugins list (ignore, ignore_stateless, ignore_arg, expect_any_args, array, callback, cexception, return_thru_ptr) and what each enables, mock-suffix and mock-prefix conventions, how Unity teardown validates expectations, the resetTest mid-test verification, strict vs ignore argument-matching modes, and the trade-offs between mock / stub / spy / fake. Use as the CMock semantics reference when authoring Ceedling tests with mocks or when reading an unfamiliar mock-driven test suite.

74

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files
name:
cmock-reference
description:
Pure-reference catalog of CMock and Ceedling mocking semantics for C. Defines what CMock generates from a C header (the full Expect / ExpectAndReturn / ExpectAnyArgs / ExpectWithArray / Ignore / IgnoreAndReturn / IgnoreArg_{param} / ReturnThruPtr_{param} / AddCallback / Stub / ExpectAndThrow naming family), the cmock.yml :plugins list (ignore, ignore_stateless, ignore_arg, expect_any_args, array, callback, cexception, return_thru_ptr) and what each enables, mock-suffix and mock-prefix conventions, how Unity teardown validates expectations, the resetTest mid-test verification, strict vs ignore argument-matching modes, and the trade-offs between mock / stub / spy / fake. Use as the CMock semantics reference when authoring Ceedling tests with mocks or when reading an unfamiliar mock-driven test suite.
metadata:
{"keywords":"cmock, ceedling, unity, mocks, stubs, c, embedded, throwtheswitch"}

cmock-reference

Overview

CMock is, per github.com/ThrowTheSwitch/CMock, "a mock and stub generator and runtime for unit testing C" that "automagically parses your C headers and creates useful and usable mock interfaces for unit testing". Ceedling, per throwtheswitch.org/ceedling, is "a Build System for GROWING ROBUST C Projects" that "starts with the Unity test framework and CMock mock and stub generation, then adds a build system for coordinating, executing, and summarizing test and release builds".

This skill is a pure reference for CMock's generated API surface and the cmock.yml plugin model. The per-tool counterparts are ceedling-build-runner (the build orchestration) and unity-test-framework-c (the assertion API).

When to use

  • Reading a Ceedling test suite and decoding which CMock plugin produced which API.
  • Authoring a new mock for a C module - choosing between strict expectations, ignored arguments, return-thru-pointer.
  • Configuring project.yml / cmock.yml plugins for the level of strictness the team wants.
  • Migrating a legacy fake-by-hand to a CMock-generated mock.
  • Distinguishing mock / stub / spy / fake in C, where the vocabulary is fuzzier than in OO languages.

Mock / Stub / Spy / Fake in C

TermBehaviourCMock realisation
StubReturns canned values; doesn't fail the testfunc_IgnoreAndReturn(value) - no expectation, just a default return
Mock (strict)Verifies exact call + args; fails test if unmatchedfunc_Expect(args) / func_ExpectAndReturn(args, ret)
SpyRecords calls for later inspectionfunc_AddCallback(cb) - callback that records into test-scope state
FakeLightweight reimplementationfunc_Stub(impl) - replace the function with a custom C implementation

The English vocabulary is from Meszaros's xUnit Test Patterns; CMock encodes all four shapes through one generated family.

What CMock generates from a header

Given parser.h:

int parse_message(const char *buf, size_t len, message_t *out);

CMock generates mock_parser.h and mock_parser.c. The generated API for parse_message is (per github.com/ThrowTheSwitch/CMock/blob/master/docs/CMock_Summary.md):

// Strict expectations
void parse_message_Expect(const char *buf, size_t len, message_t *out);
void parse_message_ExpectAndReturn(const char *buf, size_t len, message_t *out, int retval);

// Argument-flexibility (requires :expect_any_args plugin)
void parse_message_ExpectAnyArgs(void);
void parse_message_ExpectAnyArgsAndReturn(int retval);

// Array depth (requires :array plugin)
void parse_message_ExpectWithArray(const char *buf, int buf_depth, size_t len, message_t *out, int out_depth);
void parse_message_ExpectWithArrayAndReturn(const char *buf, int buf_depth, size_t len, message_t *out, int out_depth, int retval);

// Per-argument ignore (requires :ignore_arg plugin)
void parse_message_IgnoreArg_buf(void);
void parse_message_IgnoreArg_len(void);
void parse_message_IgnoreArg_out(void);

// Whole-function ignore (requires :ignore or :ignore_stateless plugin)
void parse_message_Ignore(void);
void parse_message_IgnoreAndReturn(int retval);
void parse_message_StopIgnore(void);

// Pointer-return injection (requires :return_thru_ptr plugin)
void parse_message_ReturnThruPtr_out(message_t *val_to_return);
void parse_message_ReturnArrayThruPtr_out(message_t *val_to_return, int len);
void parse_message_ReturnMemThruPtr_out(message_t *val_to_return, size_t size);

// Callback / stub (requires :callback plugin)
void parse_message_AddCallback(CMOCK_parse_message_CALLBACK callback);
void parse_message_Stub(CMOCK_parse_message_CALLBACK callback);

// Exception throwing (requires :cexception plugin)
void parse_message_ExpectAndThrow(const char *buf, size_t len, message_t *out, CEXCEPTION_T value_to_throw);

All of the above family names are cited from the CMock Summary doc above. The generated function names follow the rigid pattern <original_function_name>_<CMockVerb>[_<paramName>].

cmock.yml :plugins list

Each generated API family is gated on a plugin in cmock.yml (typically inlined into Ceedling's project.yml under :cmock: :plugins: - per the same CMock summary doc):

PluginEnablesWhen to enable
:ignore_Ignore, _IgnoreAndReturn, _StopIgnore (stateful)When you want unmatched calls to a function to pass after _Ignore is called
:ignore_statelessSame API as :ignore but no per-test stateFaster; use when ignored functions are uninteresting
:ignore_arg_IgnoreArg_<param>When a specific argument isn't part of the assertion
:expect_any_args_ExpectAnyArgs, _ExpectAnyArgsAndReturnWhen call count matters but args don't
:array_ExpectWithArray, _ReturnArrayThruPtr_<param>When arguments are pointer-to-array of known depth
:callback_AddCallback, _StubWhen you need to capture calls or substitute a fake
:cexception_ExpectAndThrowWhen the module under test propagates CException throws
:return_thru_ptr_ReturnThruPtr_<param>, _ReturnMemThruPtr_<param>When the mocked function writes through an out-pointer

A minimal cmock.yml for a typical embedded suite:

:cmock:
  :mock_prefix: Mock
  :mock_suffix: ""
  :plugins:
    - :ignore
    - :ignore_arg
    - :expect_any_args
    - :array
    - :callback
    - :return_thru_ptr

:cexception is added only if the project uses CException.

Mock-naming convention

Per the CMock summary doc, the mock module name is built from :mock_prefix + original module name + :mock_suffix. With the default :mock_prefix: Mock:

OriginalGenerated mock module
parser.hMockparser.h and Mockparser.c
i2c_driver.hMocki2c_driver.h and Mocki2c_driver.c

In a test (test_consumer.c), include the mock header:

#include "unity.h"
#include "Mockparser.h"      // CMock-generated
#include "consumer.h"        // under test

Ceedling automatically detects the Mock* include and generates the mock at test-build time.

Test lifecycle: setUp / tearDown / resetTest

CMock hooks into Unity's per-test lifecycle:

HookWhat CMock does
setUp()(Optional) Mockparser_Init() clears prior expectations - Ceedling generates this automatically when test_runner is generated
tearDown()Mockparser_Verify() asserts every queued expectation was matched; fails the test via Unity assertion if not
resetTest() (mid-test)Per the CMock summary doc, "Call it during a test to have CMock validate everything to this point and start over clean" - useful for staged interaction tests

Forgetting to register a mock causes link errors, not test failures - the mock is the only definition of the symbol.

Argument-matching modes

CMock's default mode is strict by argument: passed arguments must memcmp-equal the expected. The user softens with:

SoftenerEffect
_IgnoreArg_<param>This call's <param> is not checked
_ExpectAnyArgsNone of this call's args are checked
_Ignore / _IgnoreAndReturnAll subsequent calls to this function are ignored until _StopIgnore
Custom matcher via _AddCallbackInspect args programmatically and return a comparison

For pointer arguments to structs, the default is deep-equal by size - CMock memcompares the pointed-to memory. For string pointers, treat as strcmp only if the deep-equal of the buffer matches the string length CMock chose at generation; in practice, use _IgnoreArg_<param> + a _AddCallback for string-matching.

Worked example

A consumer module that calls a parser; the test verifies the expected call shape:

// consumer.h - under test
int consume(const char *raw);

// consumer.c
#include "parser.h"
int consume(const char *raw) {
    message_t m;
    if (parse_message(raw, strlen(raw), &m) != 0) return -1;
    return m.kind;
}

// test_consumer.c
#include "unity.h"
#include "Mockparser.h"
#include "consumer.h"

void test_consume_returns_kind_on_success(void) {
    message_t out_fixture = { .kind = 7 };

    parse_message_ExpectAndReturn("PING", 4, NULL, 0);
    parse_message_IgnoreArg_out();
    parse_message_ReturnThruPtr_out(&out_fixture);

    TEST_ASSERT_EQUAL_INT(7, consume("PING"));
}

void test_consume_returns_negative_one_on_parse_error(void) {
    parse_message_ExpectAnyArgsAndReturn(-1);
    TEST_ASSERT_EQUAL_INT(-1, consume("BADINPUT"));
}

The first test: strict on buf + len, lenient on out, then write the fixture through the out-pointer. The second: count matters, args don't.

Anti-patterns

Anti-patternWhy it failsFix
Mocking everythingTests become assertion-by-mock; refactors break dozens of mocksMock only the boundary (driver, peripheral, OS call); leave pure logic un-mocked
_ExpectAnyArgs everywhere"Test passes" but coverage of expected call shape is zeroUse strict _Expect for the interesting args; ignore only the noisy ones
_Ignore left on globallyReal defects in the SUT-mock interaction are hiddenPair _Ignore with a clear narrative comment; prefer _IgnoreAndReturn once-per-test
Mock-side state mutation through _StubTests rely on stub side-effects across calls; hard to reason aboutUse _AddCallback to record calls explicitly; assert on the record at the end
Forgetting to enable a plugin then using its APICompile fails on unknown functionAudit :cmock: :plugins: whenever a test uses a new _IgnoreArg_* or _ReturnThruPtr_*
Mocking standard-library functionsPulls libc into mock generation; coverage explodesWrap libc behind a project-owned header (e.g. time_provider.h) and mock that
Asserting Mockxxx_Init not calledInit is generated by Ceedling, not part of the API contractDon't assert on _Init / _Destroy; assert on the domain calls

Limitations

  • CMock parses C headers, not preprocessed source. Macros that hide function declarations are invisible - generators miss them.
  • Function pointers in structs need explicit handling. CMock generates a per-symbol mock; a function-pointer field in a struct is not a symbol and isn't directly mockable. Define a typed wrapper.
  • Vararg functions partially supported. Per the CMock summary doc, vararg mocking is limited; consider wrapping a vararg function before mocking.
  • Generated code grows with module size. A 200-function header produces ~200×8 generated functions; build time matters. Split the header.
  • Argument-deep-compare can be misleading on structs with pointer members. The pointed-to memory is not recursively compared - only the pointer value. Use _AddCallback for structures-with-pointers.
  • Not thread-safe. CMock's expectation queue is per-process global state; concurrent tests in the same process collide. Ceedling runs tests serially by default - keep it that way.

References

Cited inline. Foundational documents:

Workspace
testland
Visibility
Public
Created
Last updated
Publish Source
GitHub
Badge
testland/cmock-reference badge