What is code coverage?
Code coverage (also known as structural coverage) is a measurement of how much code is executed during testing and is a metric often used to assess the completeness of requirements-based testing. In requirements-based testing, which is encouraged when following certification guidelines or standards such as DO-178C (aerospace) or ISO 26262 (automotive), source code and associated tests are derived from high- and low-level requirements.
When performing requirements-based testing, every requirement may have one or more test cases verifying its correct implementation, and all source code should be traceable to a requirement. Measuring the code coverage achieved through testing can help demonstrate this requirement traceability.
Testing code coverage
Code coverage testing can help to ensure that all source code can be traced back to requirements. This can be demonstrated by showing that, when requirements-based tests are run, 100% code coverage is achieved through either testing (of testable code) or justification (of untestable code).
DO-178C and ISO 26262 recommend the use of code coverage analysis (also known as structural coverage analysis) for measuring the effectiveness of test cases on the road to certification.
The main benefits of testing code coverage are to show that:
- Requirements are complete
- Tests are complete i.e. there is a test for every requirement
- No unnecessary code is deployed
- Deactivated code (code that is only active in configurations different from the deployed configuration) is identified
While testing code coverage manually is possible, using an automated code coverage analysis tool such as RapiCover is much more efficient and can help avoid program delays.
Types of Coverage
Different types of code coverage exist, which are used to consider code at varying levels of granularity. It is necessary to analyze code coverage at higher granularities when working with higher integrity software (e.g. higher DO-178C DAL Level or ISO 26262 ASIL).
From lowest to highest granularity, the main forms of code coverage are:
- Function coverage – has every function (or Ada subprogram) in the code been called?
- Statement coverage – has every statement been executed?
- Branch/Decision coverage – have the true and false branches of every decision in the code been executed? This type of code coverage is called Branch coverage in ISO 26262 and Decision coverage in DO-178C.
- Modified condition/decision coverage (MC/DC) – has each condition in every decision in the code been shown to independently affect the outcome of that decision? This is the most stringent code coverage metric and used with DO-178C DAL A software.
Analyzing code coverage for different languages
Whether your software is written in Ada, C or C++, code coverage is likely to be a crucial part of your software verification. If you choose to use an automated structural coverage analysis tool, you should ensure that it supports all of the languages you’re using. RapiCover supports code coverage for Ada, C, C++, and mixed language projects.
Depending on the language you’re using and coding standards you’re following, you may be unable to achieve 100% code coverage through testing alone and may need to supplement your test coverage by justifying your code as covered by analysis. Justifications may also be used for code that you’ve chosen not to test, for example because it’s more efficient to review the code structure manually.
An example of untestable code arising due to following a coding standard is that your standard could require you to include default
clauses in C switch
statements or when others
clauses in Ada case
statements.
In such a situation, you may have untestable code if all of the cases in the code include the full range of possible values.
Handling untested code
Whether untested code is untestable or you’ve simply chosen not to test it, it can either be justified manually or by using an automated code coverage analysis tool.
Manually justifying untested code would be a painstaking process, especially in larger projects. If any changes were made to code that was justified manually, considerable review effort would be needed to ensure that any justifications are applied are still valid.
Automated code coverage analysis tools that let you justify your untested code and migrate justifications such as RapiCover mitigate the cost of justifying untested code.
When your code changes, RapiCover can analyze the impact of changes on justifications and often identify the new location of justified code that has changed, even when it has moved to a different line in the source file. This can save a huge amount of review effort.