Cmocka is used as the unit testing framework for firmware.
Use the following command to build all test suites:
$ scons build-tests
It's also possible to build a specific test suite, e.g. the timer test suite:
$ scons tests/common/timer/
Run all test suites:
$ scons coverage
Run a specific test suite, e.g. the timer test suite.
$ build/unit_tests/timer/TestRunner
-
Add a new directory for the test suite in tests. It's important that the directory structure is the same as in the src directory. Assume we want to add a test suite for the src/main/encoder module, then we create tests/main/encoder.
-
Create a SConscript file with the following content
import os Import(['*']) env.Append(CPPPATH=[ '<PATH_TO_INCLUDE>' ]) env.Append(LINKFLAGS=[ '-Wl,--wrap=<FUNCTION_TO_MOCK>' ]) SOURCE = Glob('*.c') OBJECTS = env.Object(source=SOURCE) Return('OBJECTS')
-
Implement the test suite in test_MODULE_NAME.c. A basic template is included below but the existing test suites is the best place to learn how to write tests.
#include <stdarg.h> #include <stddef.h> #include <setjmp.h> #include <cmocka.h> void test_SomeImportantTest(void **state) { /* Implement test case here. */ } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_SomeImportantTest) }; return cmocka_run_group_tests(tests, NULL, NULL); }
-
Enable the test by adding the full module path to the modules list in the SConstruct file.
modules = [ os.path.join('utility', 'CRC'), os.path.join('utility', 'List'), os.path.join('utility', 'FIFO'), os.path.join('main', 'encoder'), os.path.join('main', 'interface'), os.path.join('common', 'timer') ]
If a test fails with segmentation fault GDB is a great tool to use to track down the fault.
$ gdb build/unit_tests/timer/TestRunner
This will load the test application into GDB and present the GDB console.