MC/DC vs condition coverage vs multiple condition coverage
Condition coverage takes each condition through both values. Multiple condition coverage takes every combination. MC/DC sits between: each condition shown to affect the outcome on its own, in about n + 1 tests. The machine interlock below has four conditions, so the three criteria cost four, sixteen and five tests.
The rule is start AND guard_closed AND NOT (estop OR fault): the machine runs when start is pressed, the guard is closed, and neither the emergency stop nor a fault is active. Sixteen rows. Condition coverage is met by two tests, all-TRUE and all-FALSE, which take every condition through both values and tell you nothing about any of them individually. Multiple condition coverage is all sixteen rows. MC/DC needs the engine's four independence pairs, which share scenarios and come to five distinct rows.
The pairs are: start, from the running scenario with start released (stops) to start pressed (runs); guard_closed, from guard open (stops) to closed (runs); estop, from running to estop active (stops); fault, from running to fault active (stops). Four pairs, five scenarios, and each scenario has an expected result that follows from the safety requirement rather than from the formula.
Decision coverage, also called branch coverage, is weaker still: the outcome in both values, which two tests achieve without regard to conditions. The comparison on the condition-versus-decision page uses a smaller rule to show the gap. For safety logic the point of MC/DC is the one the interlock makes obvious: a stuck estop that never affected the outcome would pass condition coverage and fail its independence pair.
Example
run := start AND guard_closed AND NOT (estop OR fault) · output
Exact checks
Truth table (16 rows)
| # | start | guard_closed | estop | fault | run |
|---|---|---|---|---|---|
| 0 | FALSE | FALSE | FALSE | FALSE | FALSE |
| 1 | FALSE | FALSE | FALSE | TRUE | FALSE |
| 2 | FALSE | FALSE | TRUE | FALSE | FALSE |
| 3 | FALSE | FALSE | TRUE | TRUE | FALSE |
| 4 | FALSE | TRUE | FALSE | FALSE | FALSE |
| 5 | FALSE | TRUE | FALSE | TRUE | FALSE |
| 6 | FALSE | TRUE | TRUE | FALSE | FALSE |
| 7 | FALSE | TRUE | TRUE | TRUE | FALSE |
| 8 | TRUE | FALSE | FALSE | FALSE | FALSE |
| 9 | TRUE | FALSE | FALSE | TRUE | FALSE |
| 10 | TRUE | FALSE | TRUE | FALSE | FALSE |
| 11 | TRUE | FALSE | TRUE | TRUE | FALSE |
| 12 | TRUE | TRUE | FALSE | FALSE | TRUE |
| 13 | TRUE | TRUE | FALSE | TRUE | FALSE |
| 14 | TRUE | TRUE | TRUE | FALSE | FALSE |
| 15 | TRUE | TRUE | TRUE | TRUE | FALSE |
Plain-language reading
Beginnerrun is true exactly when all of the following hold:
1. start is true
2. guard_closed is true
3. the following condition does not hold:
3.1. at least one of estop or fault is true (both may be true)
In every other case, run is false.
About the operators:
- AND is true only when all of its parts are true.
- NOT reverses a value: true becomes false and false becomes true.
- OR is inclusive: it is true when at least one part is true, including when several are.
Intermediaterun is true exactly when all of the following hold:
1. start is true
2. guard_closed is true
3. the following condition does not hold:
3.1. at least one of estop or fault is true (both may be true)
In every other case, run is false.
Advancedrun is true exactly when all of the following hold [conjunction ∧]:
1. start is true
2. guard_closed is true
3. the following condition does not hold [negation ¬]:
3.1. at least one of estop or fault is true (both may be true) [inclusive disjunction ∨]
In every other case, run is false.
Formal notation: start ∧ guard_closed ∧ ¬(estop ∨ fault)
Logic diagram
MC/DC
| Input | Status | Independence pair (only that input changes) |
|---|---|---|
| start | found | start=F, guard_closed=T, estop=F, fault=F → F | start=T, guard_closed=T, estop=F, fault=F → T |
| guard_closed | found | start=T, guard_closed=F, estop=F, fault=F → F | start=T, guard_closed=T, estop=F, fault=F → T |
| estop | found | start=T, guard_closed=T, estop=F, fault=F → T | start=T, guard_closed=T, estop=T, fault=F → F |
| fault | found | start=T, guard_closed=T, estop=F, fault=F → T | start=T, guard_closed=T, estop=F, fault=T → F |
The common slip
Reporting condition coverage as if it showed each condition's effect. Two tests, all-TRUE and all-FALSE, give one hundred percent condition coverage of the interlock and never demonstrate that the emergency stop does anything.
Questions
Why is MC/DC n + 1 and not 2n?
Because pairs share scenarios: the running scenario serves as one half of every pair here. In the worst case 2n tests are needed; for most rules the shared base rows bring it down to n + 1.
Does MC/DC guarantee the rule is right?
No. It guarantees that the suite shows each condition's influence on the rule as written. The expected results still have to come from the requirement, which is the pitfall page's point about coverage and correctness.
Related
Practice
See also
- Condition coverage vs decision (branch) coverage
- MC/DC explained: modified condition/decision coverage for Boolean rules
- MC/DC independence pairs, worked example with the engine’s coverage report
- Condition coverage in software testing: meaning and examples
- Decision coverage in software testing: meaning and examples
- MC/DC (modified condition/decision coverage): meaning and examples
- Machine interlock: start AND guard_closed AND NOT (estop OR fault)
- Coverage is not correctness: tests still need expected results
Testing and rules
Generated from the Tangibool engine, semantics tangibool-semantics/1, engine 1.0.0, build . Every table, map, simplification and verdict on these pages was computed by the Tangibool engine when the site was built, and every claim was re-checked by the same exact checker the app uses. Limits are stated where they apply. © 2026 Foreranger LTD.