This topic explains how to review coverage information from tests run with C/C++test. Coverage can be tracked for unit tests and manual or automated tests run at the application level.
Reviewing coverage statistics helps you measure the coverage of your current test suite and decide what additional test cases should be added. C/C++test can report a variety of code coverage types, including function, line, path, basic block, decision (branch), simple condition, and MCDC coverage metrics.
Sections include:
To view a summary of coverage information after C/C++test executes unit test cases:
Coverage statistics for the project and all analyzed files and functions will be displayed in the Coverage view. If no coverage is shown after test execution, check that 1) coverage was enabled and 2) you are displaying the type of coverage you configured C/C++test to calculate. The view’s toolbar indicates the coverage metric being displayed.
You can sort and search through the results using the available GUI controls.
When a tested file is opened in the editor, C/C++test will use green highlights to indicate which code was cover ed and pink highlights to indicate which code was not covered. Lines that are not executable will not be highlighted.
Note that you need to double-click on a function to start off path coverage view.
There is a limit for the number of coverage elements (paths, blocks etc.) that can be computed by C/C++test. When the actual number of elements on a given level (function, file or a project) exceeds the limit, which is 2147483647, C/C++test will display "N/A" in the report for a given element. In such cases, the Coverage view will contain appropriate messages, e.g. [no paths], [no blocks]. |
Knowing which test cases are related to each coverage element can help you better assess how to extend test cases to improve coverage.
To see which test cases are related to a coverage element:
To analyze the coverage for individual test cases:
Coverage statistics and coverage highlights (in the code editor) will be computed/presented for the selected test cases only.
Tip: Using Toolbar Buttons and Menus to Explore Coverage The Coverage view provides several buttons and menu commands to help you explore the coverage details reported. The buttons on the right of the toolbar allow you to collapse, delete, search for results, and synchronize with the current selection in the Test Case Explorer. In addition, the following toolbar buttons allow you to show/hide covered elements, show/hide uncovered elements, highlight the next path (for path coverage only), and highlight the previous path (for path coverage only). The drop-down menu provides commands that allow you to sort results by ascending/descending name or coverage, as well as to select the desired coverage type. |
To optimize performance, the Coverage view starts in a uninitialized mode—displaying only project-level coverage summaries. This mode is indicated with grayed project icons: Coverage in this mode may not be current—for instance, if the source code was modified outside of this IDE. You can update the coverage view by simply expanding a project node. Or, you can wait for the view to be automatically updated during execution. |
For details on configuring, generating, and reviewing reports, see Reviewing Results.
C/C++test supports the following coverage types:
To help understand how these coverage types are handled by C/C++test, be sure to read and understand the terms in the following table:
Concept | Description |
---|---|
Basic Block | A sequence of non-branching statements; a linear sequence of code with no control flow route branchings. |
Path | A unique sequence of basic blocks starting from the function entry to the point of exit. |
Decision/Branch | Decision/Branch is the possible control flow decision to be taken at the branching point in the code. C/C++test considers if-else, for, while, do-while, and switch instructions as the branching points. C/C++test does not take into account such dynamic branching points as exception handlers (throw-catch statements). |
Boolean expression | In C++, a boolean expression is simply an expression that has a 'bool' type. In C, C/C++test treats the following as boolean expressions:
|
MC/DC Decision | A top-level boolean expression composed of conditions and zero or more boolean operators. C/C++test computes MC/DC and SCC on all boolean non-constant expressions in the source code except constructor initializers and function default arguments. |
Condition | An atomic boolean non-constant expression that is a part of the MC/DC decision. A sub-expression of the MC/DC decision is considered to be a condition if it does not contain boolean operators (&&, ||, !). If a given atomic expression appears more than once in a decision, each occurrence is a distinct condition. |
Indicates how many functions in the source code were reached at least once during execution. Complete, 100% function coverage is obtained if all functions are reached at least once.
Indicates how many defined function or method calls were executed at program runtime. Complete, 100% call coverage is obtained if all functions or methods calls were executed.
Limitations:
Example:
class A { public: A() {} A(const A&) {} A(int val) {} A& foo() { return *this; } ~A() {} }; void funcA(const A& a) {} A& operator+(const A & a, const A & b) {} void defaultConstructorCall() { A objA; // Default constructor call - not included A objArr[10]; // Default constructor calls - not included A objB = objA; // Copy constructor call - not included A objC = 10; // Implicit call of A(int) constructor - not included funcA(10); // Implicit call of A(int) constructor - not included A res = objA + objA; // Operator + call - not included // Copy constructor call - not included A* objD = new A(); // Default constructor call - not included // Operator new call - not included delete objD; // Destructor call - not included // Operator new call - not included A* objE = new A[10]; // Default constructor calls - not included // Operator new call - not included delete[] objE; // Destructor calls - not included // Implicit destructor calls - not included } |
Indicates how many executable lines of source code were reached by the control flow at least once. Complete, 100% line coverage is obtained if all executable lines are reached at least once.
Indicates how many executable source code statements were reached by the control flow at least once. Complete, 100% statement coverage is obtained if all executable statements are reached at least once.
Similar to Line Coverage—except that with Block Coverage, the unit of measured code is a basic block (see the definition of this term in the previous table). This indicates how many basic blocks in the source code were reached by the control flow at least once.
Indicates if each possible path in a given function was followed by the control flow. Branching points used to single out paths (see an explanation of this term in the previous table) are the same as in Decision (Branch) Coverage.
Since loops introduce an unbounded number of paths, this measure considers only a limited number of looping possibilities. C/C++test considers two possibilities for while-loops and for-loops: zero and at least one repetition.
Execution paths resulting from special situations such as signals or exceptions thrown from functions called are not included in the set of possible execution paths. If such paths actually occur in the run time, they are counted and reported as "unexpected" ones.
In the source editor, C/C++test highlights one path at a time. To view a path in the source code editor, double-click on the appropriate function node in the Coverage view. To navigate between paths for the function, use the Highlight next element and Highlight previous element buttons in the Coverage view toolbar.
To prompt C/C++test to show only uncovered paths, disable the Highlight covered elements button in the Coverage view toolbar. To prompt C/C++test to show only covered paths, disable the Highlight not covered elements. Note that the Highlight next/prev element buttons iterate through unexpected paths only when the Highlight not covered elements button is disabled.
Indicates how many branches in source code control flow passed through. Complete, 100% coverage is obtained when every decision at all branching points took all possible outcomes at least once.
C/C++test considers the following statement types branching points in source code: if-else
, for
, while
, do-while
, and switch
. C/C++test does not take into account such dynamic branching points as exception handlers (throw-catch
statements).
If there are no decisions in a file, C/C++test reports that this metric is not available (using an "N/A" label).
MC/DC conforms to the international technical standard DO-178B/C (RTCA), which specifies the software certification criteria for mission-critical equipment and systems within the aviation industry. This includes real time embedded systems.
According to the DO-178B/C standard, the following three conditions must be satisfied to obtain complete (100%) MC/DC coverage:
Since C/C++test considers that every condition and decision can have only two outcomes for MC/DC coverage (true or false), it checks only for the third option (c) listed immediately above—since point (c) implies conditions (a) and (b). A condition is shown to independently affect the outcome of a decision by varying only that particular condition while holding fixed all other possible conditions. To test one given condition, C/C++test looks for test cases where:
Thus, to calculate the MC/DC ratio, C/C++test uses the formula
MC/DC[%] = m/n
where m
is the number of boolean conditions proven to independently affect a decision's outcome, and n
is the total number of conditions in a decision.
Note that in order to make a single condition covered, at least two test cases need to be executed: one with the condition evaluated to true
and a second with this condition evaluated to false
.
For example, consider the following code:
if (a && (b || c)) // [...] |
There are three simple conditions here: 'a', 'b' and 'c'. As a result, n (in the m/n MC/DC formula) will equal 3.
Now, let's assume that the following test cases were executed:
id | a | b | c | a && (b || c) |
---|---|---|---|---|
1 | true | true | false | true |
2 | false | true | false | false |
3 | true | false | false | false |
To compute MC/DC, C/C++test looks for the pairs of test cases where 1) the given decision was evaluated to a different value and 2) the value of only one condition changes (all other conditions remain unchanged).
In our example, there is one pair where independently changing the value of a affects the value of the complete decision:
id | a | b | c | a && (b || c) |
---|---|---|---|---|
1 | true | true | false | true |
2 | false | true | false | false |
Another pair shows that independently changing the value of b affects the value of the complete decision:
id | a | b | c | a && (b || c) |
---|---|---|---|---|
1 | true | true | false | true |
3 | true | false | false | false |
This means that our test cases proved that a and b independently affect the value of the complete decision. In terms of MC/DC coverage, they are covered and the c condition is not covered.
C/C++test will report the MC/DC coverage for such an example to be 67% [2/3 conditions covered]. You can see the actual values that the conditions and decision evaluated to in a tool tip by placing your cursor above on the condition.
Indicates the coverage for the outcomes of all decisions’ conditions. The overall number of outcomes for a decision equals 2 * n, where n is the number of conditions in a decision. Therefore, to obtain 100% coverage, all conditions must take all possible outcomes. However, to obtain non-zero coverage, one condition only needs to take one outcome.
Each condition is a boolean condition. If it evaluated to both true and false, it is marked in green. If it evaluated to either true or false, it is marked in yellow. It if did not evaluate to true or false, it is marked in pink.
To see the actual boolean value that the condition evaluated to, place your cursor above it. The value will be shown in a tool tip.
Strategies for improving coverage are discussed in Improving Test Coverage.