Shifting Left in C++ Development & Testing
Background
While researching about Test Driven Development (TDD) and software testing levels I found the following diagrams about how Shifting-Left influence the cost of software development.
Shifting-Left refers to moving testing and quality measures to earlier phases of the development lifecycle to reduce costs and improve quality.
This is very relevant for C/C++ products, because C/C++ is a very powerful language but on the other hand more error prone.
![[1] Before Shifting-Left](https://www.stickyminds.com/sites/default/files/shared/2018-12-10%20ArthurHicken%20The%20Shift-Left%20Approach%20to%20Software%20Testing%20image3.png)
![[2] After Shifting-Left](https://www.stickyminds.com/sites/default/files/shared/2018-12-10%20ArthurHicken%20The%20Shift-Left%20Approach%20to%20Software%20Testing%20image6.jpg)
In general diagram [1] illustrates the traditional approach, whereas diagram [2] visualizes the benefits of the Shift-Left approach.
What do this two charts exactly show? We have 3 curves:
- blue: Percentage of defects introduced - most done in coding phase
- orange: Defects found - most found in testing phase
- red: Costs to fix a defect - exponential growth
The charts also shows that most of defects are found in the three testing phases (expenditure in descending order):
- Unit Testing
- Functional Testing
- System Testing
The Shifting-Left theory says that the number of defects can be reduced if the testing starts early (see [2]).
C/C++ Early Testing
How can C++ developers implement early testing to reap the benefits of the Shift- Left approach.
We can split the testing in dynamic testing and static testing.
Dynamic testing verifies runtime behavior, while static testing analyzes the source code to identify potential issues early.
Dynamic testing
The basic of the dynamic testing in a first step should be the introduction of unit tests. The recommendation would be to plan how to introduce Unit tests to the project in an early stage of the planing. There is no standard framework for unit tests in C/C++ and a lot of libraries are on the market. Additionally we could add the following tooling to analyze the data of the Unit tests:
- Code coverage
- Memory leak detection
- Performance analysis
- Mocking/Faking Framework
Static testing
Additionally static testing would enhance our code quality especially if we start with it with the beginning of the project. The following set of tools are a good entry point:
- Static code analysis
- Code formatting
CI/CD Pipeline
Static and dynamic testing should be integrated into a CI/CD pipeline to ensure they run on a regular basis. Modern Git servers like GitHub or GitLab can execute pipelines for each commit and display the results directly in the repository.
Example Tooling for a Linux C++23 Project
Let it be suppose that we have a new C++23 product. As a build tool we use CMake. The platform is Linux.
The following set of tools can be easily set up initially before staring the development phase.
Dynamic testing Tools
Unit test framework: Catch2
Memory leak detection: Valgrind
Performance analysis: Linux Perf & FlameGraph
Mocking framework: FakeIt
Catch2 and FakeIt are very easy to implement because they are header only framework. Valgrind and Perf are almost standard frameworks on Linux for memory analysis and performance messurments.
Static testing Tools
Static code analysis: Cppcheck
Code formatter: ClangFormat
Cppcheck is a community driven project that is on the market for years same as ClangFormat.
Conclusion
Shifting left in C++ development emphasizes early testing to reduce costs and improve software quality. By combining dynamic testing, static analysis, and modern CI/CD pipelines, teams can catch defects early and maintain robust, reliable code. Adopting the right tools and integrating them into your workflow ensures continuous improvement and long-term project success.