Unit Testing For Embedded C code

  • How often firmware engineers expose to unit testing?

This was an unusual topic to me at first while I have worked as firmware engineer for microcontrollers. Most of microctonroller applications are still developed in C or C++. In the past, while you developed something in C, you barely heard about unit testing. The importance of unit testing has been popular recently with newer high level languages such as Java and C#. Those languages have standard unit testing framework. Java has JUnit and Visual Studio provides a unit testing framework for C#. Unfortunately, C was developed before the rising popularity of unit testing and it did not come up with standard unit testing framework.

  • Ceedling?

From my personal experience, unit testing was introduced to me while developing functional safety products. To comply with functional safety, unit testing has to be done for the production code. This is a way to prove if the production code meets software unit's requirements & design. Since then, I have needed to do unit testing production code and research about unit testing framework. Luckily, there is new unit testing framework for C called Ceedling (throwtheswitch.org/ceedling). It is combined with Unity, CMock and CException. It resolves the worry of spending too much time to create mock functions on Unity or CPPUtest when it can be done faster. Ceedling can automatically generate mock functions for me and I do not need to write it manually.

  • Mocking Hardware

Writing software in embedded system is unique in that the software directly interacts with the hardware. For example, one of the software specifications is "Software shall be able to turn on an LED". Is this enough information to write unit test specification? No, because we do not know that turning on an LED means whether logic 1 or logic 0 on microcontroller's pin that is connected to an LED. This should be also part of software specification derived from hardware constraints. For example, "an LED shall be active-low". This means that when the microcontroller sets logic 0, an LED will turn on. Assume production code has a function named "turn_on_LED". This functionality can be tested by making a test code in Ceedling that will call the "turnon LED" function and place assertion function next line to verify if the microcontroller's pin logic is 0.

void test_turn_on_LED(void)
{
    turn_on_LED();
    TEST_ASSERT_EQUAL(0, read_LED_PIN());
}
  • Conclusion

I believe that many firmware engineers think there is not much work to do without target hardware. I was one of them, too. With unit testing, I show how to verify "turn on an LED" without hardware. This is the way unit testing works in embedded system. You will do the same test with hardware later. But at that time, if an LED does not work as expected, the issue can be addressed in hardware or specification not software. Next time, I will introduce Ceedling.

Did you find this article valuable?

Support Hyunwoo Choi by becoming a sponsor. Any amount is appreciated!