A key challenge for embedded systems developers is ensuring high-reliability operation in products designed for years-long deployments, sometimes in remote locations. A prime example of such a device is a Bluetooth-enabled environmental sensor node that performs functions such as advertising over Bluetooth Low Energy (BLE), transmitting temperature and humidity data, and supporting over-the-air (OTA) firmware updates and diagnostics.
In commercial markets, tens of thousands, hundreds of thousands, or more of these units ship over the course of the product lifecycle. Any failures in functionality or performance could have dire consequences for the manufacturer:
- Time-to-market delays can lead to missed opportunities and lost revenue as competitors capture new customers by launching similar products.
- Costly recalls erode profit as returned units are refunded, repaired, or replaced, depending on the nature of the failure.
- Security vulnerabilities can cause service disruptions and data breaches that further damage brand reputation and the likelihood of repeat business with customers.
To avoid these pitfalls, development teams can leverage automation and modern engineering practices for faster ad-hoc testing and bug remediation. Still, this can be challenging when working with manual build processes across distributed teams using inconsistent toolchains. Dojo Five EmbedOps helps embedded teams quickly stand up unit testing, hardware‑in‑the‑loop (HIL) testing, and automated reporting to find and address operating deficiencies that could bring down a commercial product, whether during development or after deployment.
In part 1, we investigate how EmbedOps streamlines unit testing.
BLE Sensor Node Proof of Concept
Let’s build out the example BLE-enabled environmental sensor mentioned previously into something more real. We will use a Nordic nRF52 wireless system-on-a-chip (SoC) as a baseline and start by defining some of the system’s key functions. These include:
- Periodically reading the temperature and humidity from a sensor
- Flash an LED to indicate status
- Using Nordic’s UART Service (NUS) for diagnostic echo
The EmbedOps DevKit Quickstart guide explains how to spin up a Zephyr‑based LED‑blink project that runs inside a dev container—this takes around 5 minutes to create after installing the EmbedOps CLI and required tools such as Docker.
Running the eo init command in a fresh repository will prompt users to select a preferred continuous integration (CI) platform (GitLab, GitHub, or Bitbucket) and the base container OS for the Linux distribution. Once confirmed, EmbedOps registers the project and creates the following to ensure all dev team members have the same tool versions:
- .embedops/repo_id.yml — Connects your repo to the EmbedOps platform
- .embedops/template-settings.yml — Saves your configuration choices
- .devcontainer/ — The dev container configuration
- CI configuration files for your chosen provider
Developers can then use eo add unittest to set up a unit testing framework based on Ceedling or Google Test. Alternatively, the eo add hil command is used to add HIL scaffolding. The EmbedOps CLI automatically downloads templates for test harnesses, CI scripts, and the required dev container features to conduct these tests.

eo add unittest, Step 1. Select the GoogleTest framework

eo add unittest, Step 2. Specify the source directory

eo add unittest, Step 3. Specify the test directory

eo add unittest, Step 4. Enable code coverage

eo add unittest, Step 5. The unit test template has been added successfully to the project
The EmbedOps HIL reference documentation also includes example projects such as the NUS Echo demo. This example shows the test procedure for a device that has NUS echo implemented, advertising as “EmbedOps HIL Demo Device” and echoing any data sent over NUS. The test sends data and asserts whether the received data is the same as what was sent, thereby verifying correct operation. (Note: HIL testing is explored in more detail in Part 2.)
Unit Testing
The next step is to write a unit test. Unit tests run off-target and offer fast evaluation of short sections of code—hundreds or thousands of unit tests can be conducted per second. These tests verify that each section of code performs as it should, returning the correct result for a given input.
Through unit testing, developers can catch programming and other errors, reducing the cost of fixes later in development or after deployment. In addition to localizing failures for easier troubleshooting, unit testing also allows firmware development to progress independently when hardware isn’t ready.
While embedded teams often use custom boards for hardware testing, relying purely on real-world testing slows development and blocks parallel work. To conduct effective off-target testing, firmware developers require detailed unit testing architectures and dependency injection—i.e., simulated hardware dependencies—when isolating code modules.
Additionally, different compilers, linkers, and build systems can produce test results that vary across different host machines. The key advantage of using dev container environments created by EmbedOps is that it standardizes development toolchains across the team to ensure reproducible test results.
Developers may perceive unit tests as extra work or struggle to recreate hardware dependencies when isolating firmware modules. To ease the adoption of this development best practice, the eo add unittest template creates the required scaffolding for detailed unit testing and shows examples to get developers started.
The below code snippet is a unit test covering the conversion of Zephyr sensor subsystem values into values for the respective sensor type (pressure in this example). struct sensor_value is mocking the Zephyr sensor API, allowing us to test the functionality.
For example, consider creating a test for the conversion of Zephyr sensor subsystem values into unit values for the respective sensor value types (pressure in this example). For simplicity, the tests do not include the zephyr subsystem linking it to the tests would be an unnecessary complication considering what we need to test.
The definition of the struct sensor_value is a mocking of the Zephyr sensor API allowing us to test the functionality.
struct sensor_value {
int32_t val1;
int32_t val2;
};
void setUp(void) {}
void tearDown(void) {}
void test_pressure_conversion(void) {
struct sensor_value val;
val.val1 = 1;
val.val2 = 500000;
TEST_ASSERT_EQUAL_INT32(1500, sensor_value_to_pressure(&val));
val.val1 = 0;
val.val2 = 0;
TEST_ASSERT_EQUAL_INT32(0, sensor_value_to_pressure(&val));
val.val1 = -1;
val.val2 = -500000;
TEST_ASSERT_EQUAL_INT32(0, sensor_value_to_pressure(&val));
val.val1 = 1000;
val.val2 = 999000;
TEST_ASSERT_EQUAL_INT32(1000999, sensor_value_to_pressure(&val));
val.val1 = 0;
val.val2 = 999;
TEST_ASSERT_EQUAL_INT32(0, sensor_value_to_pressure(&val));
val.val1 = 0;
val.val2 = 1000;
TEST_ASSERT_EQUAL_INT32(1, sensor_value_to_pressure(&val));
}
Unit testing frameworks like Ceedling or Google Test can be used to generate a JUnit XML report by enabling the junit_tests_report plugin in EmbedOps.

Running unit test locally on the host machine

Running unit test on GitLab CI pipeline

The Branches page on the EmbedOps platform shows the passing test

The Unit Tests page on the EmbedOps platform shows the unit test trends over time
The Consequences of Insufficient Testing
Unfortunately, there are numerous instances of commercial Bluetooth products reaching the market and failing as a result of errors that could have been prevented with sufficient unit testing. The Samsung Mobile Exynos 7885 and even Bluetooth stacks, drivers, and software development kits (SDKs) from embedded technology suppliers like Espressif Systems, TI, Microchip, and others are among them.
This roster of household name technology brands should be both comforting and cautionary. Poor testing, or not testing at all, is an industry-wide problem that plagues everyone from Fortune 500 organizations down to small teams of contractors.
EmbedOps helps build robust testing practices into development workflows by providing an intuitive, modern development infrastructure that “shifts left” testing into the development process. Dojo Five and its partners have successfully leveraged the EmbedOps framework, methodologies, and practices in countless commercial embedded products, including BLE-enabled drones, medical devices, clinical wearables, and more.
Takeaways
This article has covered several discussions of how the Dojo Five EmbedOps platform can streamline testing for verified operating quality:
- EmbedOps creates consistent build and test containers to eliminate “works on my machine” problems that are common across distributed development teams.
- The eo add unittest command is used to scaffold Ceedling and Google Test testing tools. Developers should run tests frequently using the eo test command, and these test runs can be optimized with –optimize.
- Unit tests can check that a function returns the expected result for a given input. For a function that restructures data format, for example, it tests that for a known set of input data, the code returns the data in the correct new structure or produces errors correctly.
- In embedded systems, especially, many things can’t be directly addressed through I/O-independent unit tests, such as data acquisition functionality. Here, developers must use mocks, fakes, and stubs to isolate any dependencies before unit testing—a section in this blog explains these test doubles in full.
- When unit tests reach their limits, HIL tests offer the next step for testing code performance using real-world hardware and data interactions.
Conclusion
Unit testing may seem daunting at first, but Dojo Five EmbedOps streamlines the process for consistent results across distributed teams. With a BLE sensor application example, this article has shown just how quickly teams can set up these practices using their preferred CI platform and testing framework to dramatically improve the quality of embedded products.
For developers looking to get hands-on experience with the EmbedOps platform, Dojo Five offers its EmbedOps DevKit—available from the Dojo Five team. After running through the DevKit Quickstart guide, developers can explore other EmbedOps templates, such as memory analysis and cppcheck, that support additional debugging and analysis during development.
By enabling easy adoption of thorough testing and reporting procedures, EmbedOps helps embedded teams build confidence when commercializing their products. Moreover, this testing streamlines certification so that when customers receive products, quality and reliability are assured.
Additional Resources
- – Free EmbedOps signup
- – BLE Sensor Node PoC unit testing example on Github
- – Dojo Five blog post on the benefits of unit testing for embedded systems
- – EmbedOps documentation: Introduction & Architecture
- – EmbedOps documentation: Report Generation—Unit Tests


