As with other complex software systems, test-driven development (TDD) practices offer benefits for development of embedded and system-level software. Unit testing enables a production of verified code independently from a target platform. Test-aware design supplemented with automated verification facilities significantly reduces testing time compared with manual deployment and quality assurance. Unfortunately, dependency on hardware and low-level APIs, platform limitations and portability issues can offer challenges for applying TDD techniques in practice. The presentation focuses on various approaches enabling testability of embedded and system-level code and covers such topics as TDD process, design for testability, techniques for decoupling from hardware and procedural APIs, organization of integration tests for embedded systems.
The test-driven development (TDD) process is a widely used practice that can significantly improve product quality and strengthen developers' productivity. Unfortunately, in the areas of embedded and system-level development TDD applicability faces some extra challenges. Dependencies on hardware and/or C-based system APIs, portability issues and platform limitations require more sophisticated test designs.
The presentation is aimed at encouraging and enabling software engineers involved in the aforementioned fields to apply TDD principles in practices and consists of two consecutive parts.
In the first part the TDD process will be reviewed through examples, covering how requirements can be refined using TDD and translated into unit and integration test-cases.
The second, primary, part will be focused on design principles that enable testability and anti-patterns inhibiting it. Strong focus will be given to unit testing, the technique that allows not only to verify the correctness of code but significantly bolster developer’s productivity by providing a target independent environment. Cases where decomposition and abstractions can be used to produce testable, and platform independent units will be demonstrated. Special attention will be given to dependency injection as a foundation for platform abstraction and mock testing. C++ language features, facilitating dependency injection, such as compile-time/run-time polymorphism and callbacks will be analyzed from applicability, usability and performance perspective. Techniques for mocking procedural APIs, enabling testability of system API-dependent code will be discussed. Apart from unit testing, methods and practices that can be used to organize and orchestrate automated integration tests for embedded and platform dependent code will be reviewed.
Although centered around application of TDD for embedded and system-level development with C++ language, concepts and techniques covered in the presentation are relevant for a wider range of software engineering fields.