Functional tests

Writing test cases before writing the code is generally considered an optimal practice in modern programming. Writing tests first not only speeds up the development phases, but also improves the structure of the workflow. By setting clear and measurable goals from the beginning, it is harder to introduce conceptual defects in the design of the single components, and also forces a clearer separation among the modules. More specifically, an embedded developer has less possibility to verify the correct behavior of the system through direct interaction, thus test-driven development (TDD) is the preferred approach for the verification of the single components as well as the functional behavior of the entire system, as long as the expected results can be directly measurable from the host system.

However, it must be considered that testing often introduces dependencies on specific hardware, and sometimes the output of an embedded system can only be validated through specific hardware tools, or in a very unique and peculiar usage scenario. In all these cases, the usual TDD paradigm is less applicable, and the project can instead benefit from a modular design, to give the possibility to test as many components as possible in a synthetic environment, such as emulators or unit test platforms.

Writing tests often involves programming the host so that it can retrieve information about the running target while the embedded software is executing, or alongside an ongoing debugging session, while the target executes in between breakpoints. The target can be configured to provide immediate output through a communication interface, such as a UART-based serial port, which can in turn be parsed by the host. It is usually more convenient to write test tools on the host using a higher-level interpreted programming language, to better organize the test cases and easily integrate the parsing of test results using regular expressions. Python, Perl, Ruby, and other languages with similar characteristics, are often a good fit for this purpose, also thanks to the availability of libraries and components designed for collecting and analyzing test results and interacting with continuous integration engines. A good organization of the test and verification infrastructure contributes more than everything else to the stability of the project, because regressions can be detected at the right time only if all the existing tests are repeated at every modification. Constantly running all the test cases while the development is ongoing not only improves the efficiency of detecting undesired effects as early as possible, but helps keep the development goals visible at all times, by directly measuring the number of failures, and makes the refactoring of components more affordable at any stage in the project lifetime.

Efficiency is the key, because embedded programming is an iterative process with a number of steps being repeated over and over, and the approach required from the developers is much more predictive than reactive.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.147.215