Unit Testing of Embedded Firmware – Part 5 – Continuous Integration (CircleCI)
Don’t be sad, but this is the final episode of a series that started here: https://uncannier.com/unit-testing-of-embedded-firmware-part-1-software-confucius/
This article is all easy and all gravy: supporting Test Driven Development (TDD) by getting embedded firmware unit tests running on a continuous integration server.
As per the rest of this series, the Uncannier Thunderboard projects will be the example. Thus CircleCI will be the continuous integration platform. The unit tests make use of the CppUTest harness, and are x86 unit tests running in the cloud, inside the Uncannier Thunderboard Docker container.
Although I use CppUTest as the example, this should be easily adaptable to pretty much any harness: CppUnit, Unity, Google Test, whatever.
The Uncannier Thunderboard Docker image has been modified to add all of the tools needed to build the Test build configuration, execute the unit tests, and generate an LCOV coverage report. If you have read the other parts of this series, these additions are unsurprising.
Dockerfile changes: https://github.com/gregbreen/uncannier-thunderboard-docker/commit/78d6234eb8ded448d6c257a7b6ec9f1768c867d8#diff-3254677a7917c6c01f55212f86c57fbf
# Packages needed for unit testing RUN apt-get install -y make RUN apt-get install -y gcc RUN apt-get install -y g++ RUN apt-get install -y gcc-multilib g++-multilib RUN apt-get install -y libcpputest-dev:i386 RUN apt-get install -y lcov
In this section I detail the CircleCI config.yml changes for the Uncannier Thunderboard Sense 2 project. The changes for the Uncannier Thunderboard React project are essentially identical.
Sense 2 config.yml changes: https://github.com/gregbreen/uncannier-thunderboard-sense2/commit/00fd721f2e929e8d907733e64d177f4238a18444#diff-1d37e48f9ceff6d8030570cd36286a61
React config.yml changes: https://github.com/gregbreen/uncannier-thunderboard-react/commit/fbf830f54b0d4e9d72cf9a8146503ca4fe762089#diff-1d37e48f9ceff6d8030570cd36286a61
Build The Test Configuration
Obviously the Test build configuration has to be built to produce the unit test executable. Due to the post-build step introduced in the previous article, this will also produce the LCOV coverage report.
- run: name: Build the Uncannier Thunderboard Sense 2 application - Test configuration command: /opt/SimplicityStudio_v4/studio -nosplash -application org.eclipse.cdt.managedbuilder.core.headlessbuild --launcher.suppressErrors -import uts-application -cleanBuild uts-application/Test
JUnit output is a defacto standard supported by pretty much every CI tool and test harness, allowing the CI tools to parse test results. A run step has been added to run the unit test executable again, but this time produce JUnit output.
- run: name: Generate xUnit-compatible test output command: mkdir -p JUnit; uts-application/Test/uts-application -ojunit; mv cpputest*.xml JUnit
Store Test Results
The following step tells CircleCI to parse and store the JUnit-compatible test output.
- store_test_results: path: ./JUnit
This results in CircleCI reporting test summaries for each build.
Store Code Coverage Report
CircleCI can also be told to store the code coverage report as an artifact.
- store_artifacts: path: ./uts-application/Test/Coverage destination: Coverage
And the LCOV code coverage report is directly accessible in the cloud: https://12-155989753-gh.circle-artifacts.com/0/Coverage/index.html
Once you’ve done the hard yards of getting TDD and unit testing happening on your development machine, it’s quite trivial to get it happening in your CI tool. Like I said, gravy.
Uncannier Pull Requests