CppUTest for FreeRTOS (cpputest-for-freertos) is a host PC based unit testing library supporting the unit testing of well-formed FreeRTOS based code. The purpose is to enable rapid TDD unit testing with host-PC based testing of FreeRTOS based firmware. It provides various FreeRTOS functions as non-functional linking only replacements or ‘fakes’ providing equivalent functionality for the unit-under-test. FreeRTOS timers are a great example, where this library provides functional-but-fake timers, where control of the fake timers is left to the unit tests themselves.
Alert readers might already be asking themselves: what are “well-formed” modules? Well-formed in this context means a module with a single thread employing a single blocking mechanism, such as a queue or semaphore. When unblocked the primary behavior of the thread is activated. A well-known example would be an active object. Frankly, any thread design employed in firmware should be well-formed. Like many others, I consider the mixing of RTOS blocking and locking mechanism’s to be a recipe for a bad-cake, if not disaster. Two separate examples are provided to demonstrate how to design the module to enable unit testing in this environment. Other approaches are possible, but the more a unit-under-test deviates from the above pattern, the more difficult it will be to unit test.
So what is the benefit? Easier TDD. Faster TDD. Host-PC unit testing. Module privates are easier to keep private. How?
Take a look at timers. If a module is using FreeRTOS timers to create timed behavior and we want to employ host-PC based unit testing, how do we do that? Options include:
- Actually run the PC version of FreeRTOS, allowing the thread and timers to execute per normal. (too slow, too heavy… what if a timer is set for minutes?)
- Expose the internal timer callback, and execute that callback from a unit test directly. (Exposes internal module details. No thank you.)
- If the module is a active object, we might inject a unit-test created message into the module’s queue that is the equivalent of what the module expects when a timer fires. (Again, exposes internal module details.)
- Or, and this is what this library enables, we provide a fake-but-functional timer subsystem adhering to the FreeRTOS API and its associated requirements. Then we provide an API, such as
cms::test::MoveTimeForward(...). This allows the unit test to use natural expressions such as “move time forward 5 seconds”. The internal timers then immediately tick the equivalent of 5 seconds, firing timer callbacks as required, but almost instantly, suitable for unit-testing. THIS IS THE WAY! The unit test will read more like a requirement document and the test does not need to access any internal private details.
Where does the library stand currently? See the below table (reflecting v1.1.0, as of Nov 14, 2024). Please note that none of the provided “fake but functional” items will ever block. Blocking is bad while unit testing, as I want my tests to execute fast and reliably.
| Item | Status |
|---|---|
| FreeRTOS version | Currently developed against v11.1.0 |
| Task API | Link only. Tasks are never created. |
| Queues | Fake but functional. |
| Queue Sets | Fake but functional. |
| Timers | Fake but functional, with namespace’d control methods provided to allow unit tests to control the passage of time. Additionally, timers are coordinated with vTaskDelay, xTaskGetTickCount, and related APIs. |
| Semaphores | Fake but functional. |
| Mutexes | Fake but functional. Additionally (kinda cool), after the conclusion of each unit test, the library will confirm that all mutexes are destroyed OR are in an unlocked state. |
| Direct to task notifications | TODO |
| Stream Buffers | TODO |
| Message Buffers | TODO |
| Event Groups | TODO |
An early inspiration for this effort may be found in this past post: “Unit Testing of Active Objects…” Take a look to learn more.
Licensing is GPL or Commercial. Commercial product-line licenses will be free for any entity that engages in a consulting or code review engagement with myself. Please contact me for details.
I hope this library will grow and prove useful to many firmware teams using FreeRTOS. Take a look at it on github!
Related references: