Embedded CI/CD pipelines create a fault-tolerant development environment in which every change is tested automatically before it goes into the shared code base. At the core, unit tests form a safety net that makes regressions visible. Combined with automatic mock generation, a standardized build system and integrated documentation, this lets teams secure ASPICE-compliant quality systematically.
Key Takeaways
- Unit tests don’t prove the quality of today’s code. They are a safety net for every future change: the more tests a team has, the more calmly it can keep developing its software.
- When you fix a bug, you first write a test that reproduces it, which tightens the safety net instead of just patching the bug.
- Marquardt relies on its own open source platform, SPLE, which combines CMake, Google Test, KConfig and the in-house automocker Hammocking into one consistent development environment for embedded C.
- Sphinx-based documentation generation keeps requirements, test specifications and test results in the same source code repository and produces ASPICE-compliant component reports from them.
Why Embedded Teams with a Hardware Background Struggle with Software Quality
Embedded software often starts out in tinkering mode, and that is exactly what causes trouble later, long before anyone thinks about embedded CI/CD. People who come from hardware development rarely begin with a well-designed build environment. They hack together a first version, the LED blinks, and that’s the moment of joy.
Karsten Günther describes this thrill as the heart of programming: you build something, and in the end it does something. In embedded, you get there quickly. As long as the product stays small, that mode works.
Complexity is where it breaks. As soon as a product is sold and several customers bring their own requirements, hacking isn’t enough anymore. You need automated tests to keep quality consistent. Many companies with a strong hardware heritage hit this same wall.
At Marquardt, a manufacturer of battery management systems, touch panels, LED strips and control elements, most software developers originally come from hardware. That leaves a gap in software development that individual tools can’t close. It takes a different way of working.
What Embedded CI/CD Is Really Supposed to Achieve
CI/CD is the answer to automation and repeatable testing. If you want to automate your regression tests and run them again and again, there is no way around continuous integration.
Continuous integration means merging changes into a mainline several times a day and making them available to everyone. Several people work on one code base, every change gets tested, and quality stays at the same level.
The real goal goes deeper than the technology. Continuous integration is meant to create a fault-tolerant environment. When someone makes a mistake, that one person should get the feedback, not the whole organization.
Karsten recalls an early job where he was told: this is your code, you’re responsible for it, but don’t you dare change anything, you might break something. For a software developer, that’s a contradiction. Changing software is the job. If change is dangerous, the safety net is missing.
Platform Engineering: Developers Build Products, Not Build Systems
No developer wants to run a build system. Developers enjoy implementing functionality, not maintaining tools. That’s where platform engineering comes in.
Marquardt is building a standardized platform for software product line engineering, known internally as SPLE. It gives developers everything they need to develop their product, make it configurable and create variants.
Variants aren’t a side issue here. They are the business model. Marquardt sells to customers who sit between the manufacturer and the end user and want their own customization. An LED in a car, a button on a washing machine, a battery management system: every customer wants something tailored.
The platform’s job is to put developers in a position to configure their software, test that configuration and integrate their changes without breaking anything.
Test-Driven Development Gives You a Safety Net, Not Proof
A test doesn’t prove that your current code works. That reversal is at the core of test-driven development. If you solve a simple task, like adding two numbers, you can write working code without a test.
The value only shows up when the software grows. When new requirements come in, nobody knows every feature that’s already been implemented in detail. The chance of breaking something old while making a change is real.
That’s where the safety net comes in. Existing tests catch you. If a developer makes a mistake while implementing a new requirement, a test fails and they immediately see what they broke. The more tests, the more relaxed the work.
“You first write a test to reproduce the bug. And that’s not wasted effort, because this test only makes your safety net tighter.”
(Karsten Günther)
Karsten calls this a gift. Even when fixing a bug, you start with a test that reproduces it. That test stays and permanently tightens the net. Over the years, a component grows to thousands of unit tests that run on every change and give fast feedback. No software is bug-free, but the tighter the net, the lower the chance of breaking old features without noticing.
The Building Blocks of a CI/CD Pipeline for Embedded C
Marquardt’s SPLE platform rests on several specific tools, most of them open source. They mesh together rather than just sitting side by side.
| Building Block | Function |
|---|---|
| CMake | build system, mature and powerful, maintained for many years |
| Git with branch protection | trunk-based development, changes have to pass a gate |
| Google Test | C++-based test framework used as the test runner |
| Hammocking | in-house Python package for automatic mock generation |
| Sphinx | documentation generator for reports and requirements tracing |
CMake is the foundation of the build environment. Marquardt extended it to support software product line engineering, and with it variants, which CMake doesn’t offer out of the box. KConfig, some PowerShell and Python round it out.
Google Test brings the full power of object-oriented C++ to testing. For developers from a pure C background, getting started is a technical hurdle because Google Test is C++. Once you’re over it, you can do things you would otherwise know from Java or Python.
Hammocking: Generating Mocks Automatically Instead of Cutting Them by Hand
C development lacks the mocking support that object-oriented test frameworks often provide. In unit testing, you have to cut the unit under test free from its external interfaces. Those dependencies need to go.
Marquardt built its own tool for this: Hammocking, a Python package that generates mocks automatically. The name is a play on words combining hammock and mock. It lets you use the return values of external interfaces as input or output vectors in unit tests.
Hammocking is open source and available on GitHub. Marquardt uses it internally but keeps developing it in public. The same goes for the entire SPLE platform, which anyone can download and install.
Documentation Belongs with the Code, Not in a Separate Tool
Reporting and compliance evidence can live on the same platform used for testing. Marquardt uses Sphinx for this, the documentation tool from the Python world that powers many Read the Docs sites.
Through Sphinx extensions, the platform covers requirements tracing, test specification generation and automatic test reports. The documentation is ASPICE-compliant for unit construction, because users inside the company asked for traceability to requirements and for a way to write software requirements.
The advantage is where it lives. All documentation sits in the source code repository, right next to the code. For each component, you can generate a report that brings together the design spec, test specification and test results.
The test specification is generated from the Google Test suites, and the test results are pulled in directly. That way, the path from requirement to test result is ASPICE-compliant, with no breaks between tools.
Where an Embedded Platform Needs to Go Next
The next stage is spreading it across the company. Over the next two years, the goal is to move as many projects as possible that still run on older technology onto the SPLE platform. Users already accept it widely.
In terms of content, ASPICE goes beyond unit construction. ASPICE describes the entire V-model, and that’s exactly the direction: the platform should support the V-model as far as software development needs it.
In practice, that means hardware in the loop, software in the loop, software integration testing and system integration testing. The platform should lay the groundwork so these test levels are as easy as possible to implement. Step by step, a build system for unit tests turns into a consistent quality environment.
Frequently Asked Questions
At what point is quick-and-dirty coding no longer enough in embedded projects?
The turning point comes with complexity. As long as the product remains small, the “tinkering” approach works: cobble together some code, the LED flashes, and you’re done. As soon as a product is sold and multiple customers have their own requirements, that’s no longer enough. Then you need automated tests to maintain consistent quality. Companies with a strong legacy of hardware are particularly affected.
What is the purpose of continuous integration beyond mere automation?
The actual goal is a fault-tolerant environment. Changes are merged into a mainline several times a day and are available to everyone, with each one tested. If someone makes a mistake, that one person receives the feedback, not the entire organization. The opposite approach is: “This is your code, but don’t change a thing, you might break something.”
What’s the point of unit tests if simple functions can be written correctly even without testing?
A test does not prove that the current code works. If you’re adding two numbers, you don’t need a test. The value becomes apparent with extensions: When new requirements are added, no one knows all the implemented features in detail anymore. Existing tests then immediately show which old behavior the change has broken.
Is it worth writing a test first when fixing a bug?
Yes. The test reproduces the bug before the fix is implemented and remains part of the codebase permanently. This isn’t a waste, because it tightens the safety net. Over the years, a component can accumulate thousands of unit tests that run with every change. This doesn’t make software bug-free, but it reduces the risk of unnoticed regressions.
Why does a dedicated platform team manage the build and test environment?
No developer wants to operate a build system. Developers enjoy implementing functionality, not maintaining tools. The platform should empower them to make software configurable, perform configuration testing, and integrate changes without collateral damage. At Marquardt, variant creation is no minor matter: every customer wants their own customization.
Why is unit testing in C more complex than in object-oriented languages?
C development lacks the mocking capabilities that object-oriented testing frameworks often provide. The element under test must be decoupled from its external interfaces; the goal is to resolve dependencies. To address this, Marquardt developed Hammocking, a Python package that automatically generates mocks. This allows return values from external interfaces to be used as input or output vectors in unit tests.
Where should test documentation for ASPICE compliance be stored?
In the source code repository, right alongside the code, rather than in a separate tool. Marquardt generates requirements traceability, test specifications, and test reports using Sphinx extensions. A report is created for each component, bringing together the design specification, test specification, and test results. The test specification is generated from the Google test suites, ensuring that the path from requirement to result remains traceable without tool discontinuities.
Which test levels are missing if a platform covers only unit tests?
In ASPICE, unit tests cover only the Unit Construction level. However, ASPICE describes the entire V-model. For the subsequent stages, hardware in the loop, software in the loop, software integration testing, and system integration testing are missing. An embedded platform must therefore lay the groundwork to ensure that these test levels can be implemented as easily as possible.


