Beyond Decision Coverage

In the previous lesson, you learned about statement and decision coverage. Decision coverage ensures every branch is exercised, but it does not tell you whether individual conditions within a compound decision are truly tested. Consider this code:

if sensor_active and temperature > threshold and not emergency_override:
    activate_cooling_system()

Decision coverage only requires two test cases — one where the entire expression is True and one where it is False. But which condition caused the False outcome? Decision coverage does not care. For a cooling system in a nuclear plant, that distinction is critical.

This is where condition-level coverage criteria come in, culminating in MC/DC — the most rigorous practical coverage measure used in safety-critical industries.

Condition Coverage

Condition coverage requires that each individual condition in a decision takes both True and False values across the test suite.

For the decision A AND B:

TestABDecision
1TFF
2FTF

This achieves 100% condition coverage — both A and B take True and False values. But notice: the decision outcome is False in both cases. We never tested the True branch. Condition coverage alone can miss entire branches.

Branch/Condition Coverage

Branch/condition coverage combines both requirements: every condition must take both values AND every branch must be exercised.

For A AND B:

TestABDecision
1TTT
2FFF

Now we cover both branches and both conditions take True and False. But there is still a gap — we cannot tell if A independently affects the outcome, because A and B always change together.

Multiple Condition Coverage

Multiple condition coverage (MCC) requires testing every possible combination of condition values. For A AND B, that means:

TestABDecision
1TTT
2TFF
3FTF
4FFF

This is thorough but impractical for real-world code. With N conditions, you need 2^N test cases. A decision with 10 conditions requires 1,024 tests. For 20 conditions: over a million.

Modified Condition/Decision Coverage (MC/DC)

MC/DC is the practical sweet spot. It was developed by NASA and Boeing in the 1990s for avionics software and became the required coverage criterion for safety-critical aviation software under DO-178B (now DO-178C).

MC/DC requires:

  1. Every entry and exit point is invoked (basic block coverage)
  2. Every condition takes both True and False (condition coverage)
  3. Every decision takes both True and False (decision coverage)
  4. Each condition independently affects the decision outcome — for each condition, there exists a pair of test cases where only that condition changes value and the decision outcome changes

Rule 4 is what makes MC/DC special. It proves that each condition actually matters.

Deriving MC/DC Test Cases

For the decision A AND B AND C, follow this systematic process:

Step 1: Build the complete truth table.

#ABCResult
1TTTT
2TTFF
3TFTF
4TFFF
5FTTF
6FTFF
7FTFF
8FFFF

Step 2: Find independence pairs for each condition. An independence pair for condition X is two rows where X changes, all other conditions stay the same, and the decision outcome changes.

  • Condition A: Rows 1 (T,T,T→T) and 5 (F,T,T→F) — A changes, B and C stay T, outcome changes
  • Condition B: Rows 1 (T,T,T→T) and 3 (T,F,T→F) — B changes, A and C stay T, outcome changes
  • Condition C: Rows 1 (T,T,T→T) and 2 (T,T,F→F) — C changes, A and B stay T, outcome changes

Step 3: Select the minimum set covering all pairs: rows {1, 2, 3, 5} = 4 test cases.

For N conditions with AND: N+1 test cases. For N conditions with OR: also N+1. This is dramatically better than the 2^N required by multiple condition coverage.

MC/DC for Mixed Operators

When a decision mixes AND and OR, the process is the same but finding independence pairs requires more care.

For (A OR B) AND C:

#ABCA OR BResult
1TTTTT
2TTFTF
3TFTTT
4TFFTF
5FTTTT
6FTFTF
7FFTFF
8FFFFF

Independence pairs:

  • A: Rows 3 (T,F,T→T) and 7 (F,F,T→F) — A changes, B=F, C=T held constant
  • B: Rows 5 (F,T,T→T) and 7 (F,F,T→F) — B changes, A=F, C=T held constant
  • C: Rows 1 (T,T,T→T) and 2 (T,T,F→F) — C changes, A=T, B=T held constant

Minimum set: {1, 2, 3, 5, 7} = 5 test cases. Mixed operators may require slightly more than N+1.

Where MC/DC Is Required

MC/DC is not just an academic exercise. It is mandated by real standards:

StandardDomainMC/DC Required For
DO-178CAviationLevel A (catastrophic failure) software
ISO 26262AutomotiveASIL D (highest risk) software
IEC 61508IndustrialSIL 4 (highest safety integrity)
EN 50128RailwaySIL 3 and SIL 4 software

If you work in any of these industries, MC/DC is not optional — it is a regulatory requirement.

Tools for MC/DC Analysis

Several tools support MC/DC measurement:

  • VectorCAST — Industry standard for embedded and safety-critical systems
  • LDRA — Widely used in aerospace and automotive
  • Parasoft C/C++test — Supports MC/DC for C and C++ codebases
  • gcov + custom analysis — Open-source option for basic condition tracking
  • JaCoCo — Java coverage tool that supports branch coverage (not full MC/DC, but useful as approximation)

Exercise: Derive MC/DC Test Cases

Problem 1

Given the function:

def should_trigger_alert(pressure_high, temp_critical, manual_override):
    return (pressure_high or temp_critical) and not manual_override

Derive the minimum MC/DC test set.

Solution

Build the truth table for (A OR B) AND NOT C where A=pressure_high, B=temp_critical, C=manual_override:

#ABCNOT CA OR BResult
1TTFTTT
2TFFTTT
3FTFTTT
4FFFTFF
5TTTFTF
6TFTFTF
7FTTFTF
8FFTFFF

Independence pairs:

  • A (pressure_high): Rows 2 (T,F,F→T) and 4 (F,F,F→F)
  • B (temp_critical): Rows 3 (F,T,F→T) and 4 (F,F,F→F)
  • C (manual_override): Rows 2 (T,F,F→T) and 6 (T,F,T→F)

Minimum set: {2, 3, 4, 6} = 4 test cases.

Testpressure_hightemp_criticalmanual_overrideExpected
1TrueFalseFalseTrue
2FalseTrueFalseTrue
3FalseFalseFalseFalse
4TrueFalseTrueFalse

Problem 2

A flight control system has this logic:

if (altitude_low && airspeed_low && !landing_gear_deployed) {
    trigger_terrain_warning();
}
  1. How many test cases does MC/DC require?
  2. How many does multiple condition coverage require?
  3. Derive the MC/DC test set.
Solution

Decision: A AND B AND NOT C where A=altitude_low, B=airspeed_low, C=landing_gear_deployed.

  1. MC/DC requires 4 test cases (N+1 = 3+1, since NOT C is still one condition)
  2. Multiple condition coverage requires 8 test cases (2^3)

Truth table:

#ABCNOT CResult
1TTFTT
2TTTFF
3TFFTF
4FTFTF

Independence pairs:

  • A: Rows 1 and 4 (A changes T→F, B=T, C=F fixed, result T→F)
  • B: Rows 1 and 3 (B changes T→F, A=T, C=F fixed, result T→F)
  • C: Rows 1 and 2 (C changes F→T, A=T, B=T fixed, result T→F)

Minimum MC/DC set: {1, 2, 3, 4} — exactly 4 tests instead of 8.

Practical Tips for MC/DC

Simplify before analyzing. If a condition contains redundant sub-expressions, simplify using Boolean algebra first. MC/DC on a simplified expression requires fewer tests.

Coupled vs. uncoupled conditions. When two conditions share a variable (e.g., x > 5 AND x < 10), you cannot vary one independently of the other. This is called a coupled condition. Coupled conditions may require different independence pairs than uncoupled ones.

Use masking MC/DC for complex expressions. In masking MC/DC (allowed by DO-178C), a condition can be shown to independently affect the decision even if other conditions change, as long as the changes are “masked” (do not affect the outcome through the logical structure). This can reduce the required test set further.

Short-circuit evaluation matters. In languages with short-circuit evaluation (most modern languages), A AND B does not evaluate B if A is False. This means some MC/DC test cases may not actually exercise certain conditions at runtime. Consider whether your coverage tool accounts for short-circuit behavior.

Key Takeaways

  • Condition coverage tests individual conditions but can miss branches entirely
  • Branch/condition coverage combines both but does not prove independence
  • MC/DC proves each condition independently affects the decision outcome
  • MC/DC requires N+1 test cases (vs. 2^N for multiple condition coverage) — practical even for complex decisions
  • MC/DC is mandated by DO-178C, ISO 26262, and IEC 61508 for safety-critical software
  • Always find independence pairs systematically using truth tables
  • Consider coupled conditions, short-circuit evaluation, and masking MC/DC for complex real-world decisions