Embedded Systems Architecture
上QQ阅读APP看书,第一时间看更新

Continuous integration

As previously mentioned, the test-driven approach is crucial in an embedded environment. Automating the tests is the best way to promptly detect regressions, and defects in general, while the development is ongoing. Using an automation server, such as Jenkins, it is possible to plan several actions, or jobs, to run responsively (such as at every commit), periodically (such as every Tuesday at 1 a.m.), or manually, upon user requests. Here are a few examples of jobs that can be automated to improve the efficiency of an embedded project:

  • Unit tests on the development machine
  • System validation tests
  • Functional tests on a simulated environment
  • Functional tests on a physical target platform
  • Stability tests
  • Static code analysis
  • Generating documentation
  • Tagging, versioning, packaging

The desired level of quality must be decided during design, and test cases must be coded accordingly. Unit test code coverage can be measured using gcov upon each test execution. Some projects intended for life-critical applications may require a very high percentage of coverage for unit tests, but writing a complete set of tests for a complex system has a great impact on the total programming effort, and may increase the cost of the development significantly, so researching the right balance between efficiency and quality is advisable in most cases.

A different approach has to be taken with functional tests. All the functionalities implemented on the target should be tested, and tests prepared in advance should be used to define performance indicators and acceptance thresholds. Functional tests should be run in an environment that is as close as possible to the real use case scenario, in all those cases where it is impossible to recreate the full use case on the target system and its surroundings.