There are a variety of C unit testing frameworks available however many of
them are fairly complex and require the latest compiler technology. Some
development requires the use of old compilers which makes it difficult to
use some unit testing frameworks. In addition many unit testing frameworks
assume the code being tested is an application or module that is targeted to
the same platform that will ultimately execute the test. Because of this
assumption many frameworks require the inclusion of standard C library headers
in the code module being tested which may collide with the custom or
incomplete implementation of the C library utilized by the code under test.

Cmockery only requires a test application is linked with the standard C
library which minimizes conflicts with standard C library headers. Also,
Cmockery tries avoid the use of some of the newer features of C compilers.

This results in Cmockery being a relatively small library that can be used
to test a variety of exotic code. If a developer wishes to simply test an
application with the latest compiler then other unit testing frameworks maybe
preferable.

Cmockery tests are compiled into stand-alone executables and linked with
the Cmockery library, the standard C library and module being tested. Any
symbols external to the module being tested should be mocked - replaced with
functions that return values determined by the test - within the test
application. Even though significant differences may exist between the target
execution environment of a code module and the environment used to test the
code the unit testing is still valid since its goal is to test the logic of a
code modules at a functional level and not necessarily all of its interactions
with the target execution environment.

It may not be possible to compile a module into a test application without
some modification, therefore the preprocessor symbol UNIT_TESTING should
be defined when Cmockery unit test applications are compiled so code within the
module can be conditionally compiled for tests.

Cmockery unit test cases are functions with the signature
void function(void **state). Cmockery test applications initialize a
table with test case function pointers using unit_test*() macros. This
table is then passed to the run_tests() macro to execute the tests.
run_tests() sets up the appropriate exception / signal handlers and
other data structures prior to running each test function. When a unit test
is complete run_tests() performs various checks to determine whether
the test succeeded.

Before a test function is executed by run_tests(),
exception / signal handlers are overridden with a handler that simply
displays an error and exits a test function if an exception occurs. If an
exception occurs outside of a test function, for example in Cmockery itself,
the application aborts execution and returns an error code.

If a failure occurs during a test function that's executed via
run_tests(), the test function is aborted and the application's
execution resumes with the next test function.
Test failures are ultimately signalled via the Cmockery function fail().
The following events will result in the Cmockery library signalling a test
failure...

Runtime assert macros like the standard C library's assert() should
be redefined in modules being tested to use Cmockery's mock_assert()
function. Normally mock_assert() signals a
test failure. If a function is called using
the expect_assert_failure() macro, any calls to mock_assert()
within the function will result in the execution of the test. If no
calls to mock_assert() occur during the function called via
expect_assert_failure() a test failure is signalled.

Cmockery provides an assortment of assert macros that tests applications
should use use in preference to the C standard library's assert macro. On an
assertion failure a Cmockery assert macro will write the failure to the
standard error stream and signal a test failure. Due to limitations of the
C language the general C standard library assert() and Cmockery's
assert_true() and assert_false() macros can only display the expression that
caused the assert failure. Cmockery's type specific assert macros,
assert_{type}_equal() and assert_{type}_not_equal(), display the data that
caused the assertion failure which increases data visibility aiding
debugging of failing test cases.

To test for memory leaks, buffer overflows and underflows a module being
tested by Cmockery should replace calls to malloc(), calloc() and
free() to test_malloc(), test_calloc() and
test_free() respectively. Each time a block is deallocated using
test_free() it is checked for corruption, if a corrupt block is found
a test failure is signalled. All blocks
allocated using the test_*() allocation functions are tracked by the
Cmockery library. When a test completes if any allocated blocks (memory leaks)
remain they are reported and a test failure is signalled.

For simplicity Cmockery currently executes all tests in one process.
Therefore all test cases in a test application share a single address space
which means memory corruption from a single test case could potentially cause
the test application to exit prematurely.

A unit test should ideally isolate the function or module being tested
from any external dependencies. This can be performed using mock functions
that are either statically or dynamically linked with the module being tested.
Mock functions must be statically linked when the code being tested directly
references external functions. Dynamic linking is simply the process of
setting a function pointer in a table used by the tested module to reference
a mock function defined in the unit test.

In order to simplify the implementation of mock functions Cmockery provides
functionality which stores return values for mock functions in each test
case using will_return(). These values are then returned by each mock
function using calls to mock().
Values passed to will_return() are added to a queue for each function
specified. Each successive call to mock() from a function removes a
return value from the queue. This makes it possible for a mock function to use
multiple calls to mock() to return output parameters in addition to a
return value. In addition this allows the specification of return values for
multiple calls to a mock function.

In addition to storing the return values of mock functions, Cmockery
provides functionality to store expected values for mock function parameters
using the expect_*() functions provided. A mock function parameter can then
be validated using the check_expected() macro.

Successive calls to expect_*() macros for a parameter queues values to
check the specified parameter. check_expected() checks a function parameter
against the next value queued using expect_*(), if the parameter check fails a
test failure is signalled. In addition if check_expected() is called and
no more parameter values are queued a test failure occurs.

Cmockery allows the specification of multiple setup and tear down functions
for each test case. Setup functions, specified by the unit_test_setup()
or unit_test_setup_teardown() macros allow common initialization to be
shared between multiple test cases. In addition, tear down functions,
specified by the unit_test_teardown() or
unit_test_setup_teardown() macros provide a code path that is always
executed for a test case even when it fails.

A small command line calculator
calculator.c application
and test application that full exercises the calculator application
calculator_test.c
are provided as an example of Cmockery's features discussed in this document.