主要内容

Decision Coverage

Percentage of decision outcomes that current test cases cover

Since R2023b

Description

Decisions are Boolean expressions that can combine multiple conditions by using logical operators such as && or ||. For a definition of a condition, see Condition Coverage. Conditions within branching constructs (if-else, while, do-while, switch-case) are decisions.

Each decision in your code has two outcomes: true and false. This metric indicates the percentage of decision outcomes in your source code that the current test cases evaluate. For instance, a decision coverage of 50% indicates that the test cases evaluate half of the decision outcomes in your code at least once. To increase decision coverage, add test cases to evaluate any unevaluated decision outcomes.

Polyspace Implementation

To calculate the decision coverage, Polyspace® counts the total number of possible decision outcomes (n_outcome) and the decision outcomes the test cases evaluate (n_evaluated):

Decision coverage = (n_evaluated / n_outcomes) *100
For instance, consider this code:
int foo(int x)
{
    int y = (x >= 5 && x != 7); //1

    if (x < 0)//2
        return 1;
    else if (x > 0 && y)//3
        return 2;
    else
        return -1;
}
The decisions in this code are:

  • (x >= 5 && x != 7)

  • (x < 0)

  • (x > 0 && y)

Each of these decisions can be either true or false, resulting in n_outcomes = 6. Polyspace counts how many of these outcomes the test case evaluates. For instance, if you test foo() with x == 0, then the test case evaluates only the false outcome of all three decisions, resulting in coverage of 3/6×100, or 50%.

Examples

expand all

Consider the function foo(), which contains three decision statements with six possible decision outcomes.

int foo(int x)
{
    int y = (x >= 5 && x != 7);

    if (x < 0)
        return 1;
    else if (x > 0 && y)
        return 2;
    else
        return -1;
}

Suppose you write the following test cases for the function.

Test Case 1Test Case 2

  • Input: Parameter value = -1

  • Assessment: Return value == 1

  • Coverage: (2/6)×100 or 33%

  • Coverage Details: This test case evaluates two out of the six possible decision outcomes.

    int foo(int x)
    {
        //False covered
        int y = (x >= 5 && x != 7);
        //True covered
        if (x < 0)
            return 1;
        else if (x > 0 && y)
            return 2;
        else
            return -1;
    } 

  • Input: Parameter value = 5

  • Assessment: Return value == 2

  • Coverage: (3/6)×100 or 50%

  • Coverage Details: This test case evaluates three out of the six possible decision outcomes.

    int foo(int x)
    {
        //True covered
        int y = (x >= 5 && x != 7);
        //False covered
        if (x < 0)
            return 1;
        else if (x > 0 && y)//True
            return 2;
        else
            return -1;
    } 

The two preceding test cases evaluate five of the six decision outcomes in foo().

DecisionOutcomeCoverage
(x >= 5 && x != 7)trueCovered by test case 2
falseCovered by test case 1
(x < 0)trueCovered by test case 1
falseCovered by test case 2
(x > 0 && y)trueCovered by test case 2
falseNot covered

The combined decision coverage of the preceding two tests is 5/6×100, or 83%. To test all decisions in foo(), add a new test case that evaluates (x > 0 && y) to false.

Correction — Add Test Case to Complete Decision Coverage

To obtain 100% decision coverage, add a third test case:

  • Input — Parameter value = 0

  • Assessment — Return value = -1

  • Coverage — (3/6)×100 or 50%

  • Coverage Details — This test case evaluates three out of the six possible decision outcomes.

    int foo(int x)
    {
        int y = (x >= 5 && x != 7);//False covered
    
        if (x < 0)//False covered
            return 1;
        else if (x > 0 && y)//False covered
            return 2;
        else
            return -1;
    } 

The additional test case evaluates the false outcome of (x > 0 && y), resulting in 100% decision coverage.

Consider the following source code:

  • Include file types.h:

    typedef enum Sign {
        POS,
        ZERO,
        NEG
    } Sign;

  • Source file:

    #include "types.h"
    
    int getRepresentativeNumber(Sign inputSign) {
        switch (inputSign) {
          case POS:
            return 1;
          case NEG:
            return -1;
          default:
            return 0;
        }
    }

Suppose you write the following test case for the function getRepresentativeNumber():

  • Input: inputSign = POS

  • Assessment: Return value (pst_call_out) == 1

The decision coverage is as follows:

  • Coverage: (1/3)×100 or 33%

  • Coverage Details: This test case evaluates one out of the three possible decision outcomes. The total number of possible decision outcomes in a switch-case expression is the number of case clauses plus one.

    int getRepresentativeNumber(Sign inputSign) {
        switch (inputSign) {
          // Outcome covered
          case POS:
            return 1;
          // Outcome not covered
          case NEG:
            return -1;
          // Outcome not covered
          default:
            return 0;
        }
    }

Correction – Add More Test Cases

To obtain 100% decision coverage, add two more test cases. The test cases can be as follows:

Test Case 1Test Case 2
  • Input: inputSign = NEG

  • Assessment: Return value (pst_call_out) == -1

  • Coverage: (1/3)×100 or 33%

  • Coverage Details: This test case evaluates one out of the three possible decision outcomes:

    int getRepresentativeNumber(Sign inputSign) {
        switch (inputSign) {
          // Outcome not covered
          case POS:
            return 1;
          // Outcome covered
          case NEG:
            return -1;
          // Outcome not covered
          default:
            return 0;
        }
    }

  • Input: inputSign = ZERO

  • Assessment: Return value (pst_call_out) == 0

  • Coverage: (1/3)×100 or 33%

  • Coverage Details: This test case evaluates one out of the three possible decision outcomes:

    int getRepresentativeNumber(Sign inputSign) {
        switch (inputSign) {
          // Outcome not covered
          case POS:
            return 1;
          // Outcome not covered
          case NEG:
            return -1;
          // Outcome covered
          default:
            return 0;
        }
    }

Version History

Introduced in R2023b