Parasoft Logo
Icon for embedded world in white

We're an Embedded Award 2026 Tools nominee and would love your support! Vote for C/C++test CT >>

How to Perform Unit Testing With Code Coverage on Target whitepaper cover image

Whitepaper

How to Perform Unit Testing With Code Coverage on Target

Before you jump in, get a preview below.

Jump to Section

Overview

Cross-platform testing enables running tests on target hardware with little to no change in the tool interface or usage. “Target” refers to remotely connected hardware or a simulation that resembles the runtime environment of the product under development.

Target environments run embedded operating systems on hardware more constrained by memory and performance than host development environments. The compiler/linker/debugger toolchain differs from the target processor.

The Importance of Target-Based Testing

Target-based testing or sometimes referred to as Integration-testing is essential to validate correct functionality, security, and performance of embedded systems because the host environment lacks the embedded OS, hardware interfaces, and peripherals of the end product. In addition, the performance and behavior of target systems are different than the host environment and can affect the outcome of tests.

Essential Elements of Target-Based Testing of Embedded Systems

Software verification and validation is an inherent part of embedded software development. Testing is a key way to demonstrate correct software behavior. Unit testing is the verification of the module design. It ensures that each software unit does what it’s required to do.

Additionally, safety and security requirements may require that software units don’t behave in unexpected ways and aren’t susceptible to manipulation with unexpected data inputs. Vulnerabilities may manifest in the target system due to the differences in behavior from the host environment. Attack surfaces for embedded devices are hard to simulate in host environments and proper testing requires target hardware.

Collecting and analyzing code coverage metrics is important for safety-critical software. Code coverage measures the completion of test cases and executed tests. It provides evidence that validation is complete, at least as specified by the software design.

Traceability between test cases, test results, source code, and requirements must be recorded and maintained. Therefore, data collection during target-based testing is critical.

The V-model of software development showing the relationship between each phase and the validation inferred at each stage of testing. Unit testing is highlighted as that is the topic for this page.

The V-model of software development showing the relationship between each phase and the validation inferred at each stage of testing.

Automating Target-Based Testing of Embedded Systems

Automating the testing of embedded systems is challenging due to the complexity of initiating and observing tests on embedded targets. Limited access to target hardware is another challenge that software teams face. Nevertheless, automation is essential to make embedded testing workable on a continuous basis from the host development system to the target system.

Testing embedded software is particularly time consuming. Automating the regression test suite provides considerable time and cost savings. Collecting test results and code coverage data from the target system is essential for validation and standards compliance. Target hardware may have limited physical connectivity making it more difficult to retrieve test results. Fortunately, it’s possible to extract the data from various ports, such as serial, ethernet (TCP/IP Sockets), JTAG connector, and other methods.

Performing unit testing and code coverage on target hardware

The V-model of software development showing the relationship between each phase and the validation inferred at each stage of testing.

Cross Platform Testing for Verification & Validation on Target & Host Systems

Cross-platform testing allows tests to be generated and extended on the host—the development environment where the tools are installed—and then executed onto one or more targets. This is especially useful for testing code that you cross compile for use on an embedded device or on another platform.

Parasoft C/C++test removes the barrier to effective embedded testing by automatically generating test cases that can be executed in any cross-platform situation—host, simulator, and in the actual target environments. It’s also possible to collect test results and code coverage metrics. Instrumentation detects runtime defects like memory leaks in the running applications.

Test Generation & Execution Workflow

On the host environment, developers can automatically generate a core set of unit and API test cases designed to identify unexpected function responses to corner case conditions. With a different configuration, the generated tests will capture current software behavior at the method/function level. Next steps for this test suite include:

  1. Extending as needed for functional testing.
  2. Automatic configuration for regression testing.
  3. Executing on the host, if desired, automatically replacing the target dependencies with configurable stubs.
Infographic showing The development (host) environment has all the tools to create a target executable. The target executable communicates results back to the host.
The development (host) environment has all the tools to create a target executable. The target executable communicates results back to the host.

The same test suite then gets cross-compiled, generating executables for a different processor and hardware environment for execution in a target environment. C/C++test saves and uses the target test results later in the GUI for evaluation and analysis. TCP/IP sockets can automatically send test results to the C/C++test GUI, which collects coverage metrics, including branch, simple condition, and MC/DC coverage for all tests. The C/C++test GUI provides extensive facilities for debugging test cases, including support for many host debuggers, stack trace reporting, reporting of call sequences, and detailed display of test case results.

C/C++test and C/C++test CT can instrument the original application to detect memory related problems, and then cross-compile and start on the target to pinpoint existing memory bugs to collect code coverage. Teams can combine this coverage data with that from other unit tests on host or target.

Building a Test Executable

The test executable consists of a test harness built around instrumented source code and the C/C++ runtime library. In the case of Parasoft C/C++test, it uses a prebuilt version of the C/C++test runtime library, which ships with the C/C++test distribution.

For target-based testing, teams need a cross-compiled C/C++test runtime library. C/C++test automatically prepares a build of the runtime library. In rare cases that require non-standard customization, it’s possible to manually prepare a build of the runtime library and use a cross-compiler to build the test harness source code.

C/C++test automates the process of cross compiling the test harness and linking it with the C/C++test runtime library, which requires that C/C++test correctly define the cross-compiler. This does not require user interaction.

Infographic showing the process flow for building target-based test executables.
The process flow for building target-based test executables.

The Parasoft C/C++test Runtime Library

Runtime libraries are a critical component of target-based testing since tests require an appropriate runtime environment for execution. Teams must build the runtime library with a cross compiler and appropriate libraries for execution, like the application and test cases.

Parasoft C/C++test ships with a prebuilt, full-featured runtime shared library. However, the design of this runtime is for rich host platforms. Considering the multitude of embedded platforms on which testing may occur, as well as their capabilities and limitations, teams need to adjust the runtime before building it for different embedded environments. That’s why the runtime library’s pure-C sources are also available.

Teams can configure the library to support features that are available on the target platform or to block those that are not. Embedded developers are familiar with the pros and cons of the platform(s) they use and should be able to build an appropriately configured library and append its path to the linker command line.

Working With the C/C++test Runtime Library

Parasoft C/C++test builds the runtime library automatically as a part of the test-executable preparation phase the teams system requires a custom build of the C/C++test runtime library.

The C/C++test runtime library distribution is in the form of C source and header files. In most cases, teams can let C/C++test automatically build the runtime library. If desired, teams can build the runtime library using the make utility and one of the pre-configured make configurations for the supported platforms. C/C++test provides special project files that facilitate runtime library building for popular IDEs.

Summary

Software verification and validation is an essential part of embedded software development and testing. Unit testing is necessary to ensure that each software unit does what it’s required to do. Automating testing of embedded systems is more challenging due to the complexity of initiating and observing tests on embedded targets.

Embedded software uses cross-platform testing to test on both host and target systems. Target environments are more constrained by memory and performance than host environments, and the compiler/linker/debugger toolchain is likely to be different from the target processor.

Parasoft C/C++test supports cross-platform testing and enables test automation for target-based testing. All this helps shift left target testing and increase code coverage while integrating complex target testing into CI/CD pipelines.

Team of developers

Ready to dive deeper?

Download Now