Coverage·Lab
DARK
SE401 · Software Testing and Quality · Chapter 13

You wrote the code.
Now prove it does what it does.

Black-box testing asks "does the output match the spec?" White-box testing pops the hood and asks "did we actually run every line, every branch, every condition inside it?" This chapter is the toolbox for that: code reviews that catch bugs before execution, coverage metrics that measure how much of the code your tests actually touched, and cyclomatic complexity — the number that tells you when a function has become untestable.

Static vs. Structural Testing
Fagan Inspections
5 Coverage Criteria
Cyclomatic Complexity
CONTROL FLOW A>1 AND B=0 X=X/A A=2 OR X>1
§ 01 — WHERE WHITE-BOX TESTING FITS

Bending the waterfall into a V

Every development phase has a matching testing mindset. The V-Model just draws that pairing explicitly.

🧭
Memory hook — the phase-to-test map
"Code → Unit. Low-design → Component. High-design → Integration. Software reqs → System. Business reqs → Acceptance."
Each left-side development phase has a mirror-image right-side test level. The lower down the V, the more detailed and code-focused the testing gets.
Overall Business Requirements
Software Requirements
High-Level Design
Low-Level Design
Development
Acceptance Test Design → Execution
System Test Design → Execution
Integration Test Design → Execution
Component Test Design → Execution
Unit Test Design → Execution
↳ Testing sits at the bottom point of the V, bridging Development to Unit Test Execution ↲
The rule that makes the V work: design the appropriate test for a phase during that phase, then execute it after. That's why the left side says "Test Design" and the right side says "Test Execution" — the design work happens early, in parallel with the corresponding development phase, not at the end.
Principles of the V-Model
  • Do an early test design.
  • Involve the right people in the design of the right type of tests.
  • Make the tests reflect closely the steps on the left-hand side of the V.
Unit Testing splits in two
White box testing — the focus of this chapter (Ch.13).
Black box testing — the focus of the next chapter. Unit testing is where white-box techniques live, because it's the level closest to the raw source code.
§ 02 — DEFINITION & TAXONOMY

White-box testing: two very different branches

White-box testing requires access to code. It looks at the program code and performs testing by mapping program code to functionality. It splits into two branches that are easy to conflate but test completely differently: one never runs the program, the other only runs the program.

🌳
Memory hook
"Static Stares. Structural Sprints."
Static testing stares at the source — humans or tools reading code without running it. Structural testing sprints the compiled executable against test cases to see what actually fires.
Never executes the program

Static Testing

Involves only the source code, not executables or binaries. Humans go through it, or specialized tools do.

Desk checking Code walkthrough Code review Code inspection
Runs the executable

Structural Testing

Runs the product against predefined test cases and compares actual results to expected results.

Unit / code functional testing Code coverage (statement · path · condition · function) Code complexity (cyclomatic complexity)

Why white-box testing at all?

motivation
  • The program code truly represents what the program actually does — not just what it is intended to do.
  • It minimizes delay between defect injection and defect detection (doesn't postpone detection to someone else, downstream).
  • It can catch "obvious" programming errors that don't necessarily map to common user scenarios — e.g. a divide-by-zero that only a black-box user story would never trigger.
§ 03 — STATIC TESTING

Reading code without running it

Four flavors, arranged on a single spectrum: more people, more formalism, more complex defects caught.

Static testing checks: whether the code works according to the functional requirement; whether it was written in accordance with the earlier design; whether it follows applicable standards; whether any functionality was missed; and whether the code handles errors properly. Humans can find errors computers can't, multiple humans bring multiple perspectives, and a human evaluation compares code against specs more thoroughly — it detects multiple defects at once and minimizes delay in identifying problems.

📈
Memory hook — the four types, in ascending order
"Desk → Walk → Review → Inspect" = rising formalism
As you move down this list, involvement of people increases, variety of perspectives increases, formalism increases, and the likelihood of catching complex defects increases. This is the "QA vs. QC" argument in miniature.

Desk Checking

solo · zero formalism

The author informally checks their own code against the specifications and corrects defects found. No structured method or formalism ensures completeness. No log or checklist is maintained — it relies solely on the thoroughness of the author.

Advantages
  • The programmer knows the code and language well — best suited to read the program.
  • Less scheduling and logistics overhead.
  • Reduces delay in defect detection and correction.
Disadvantages
  • Person-dependent — not scalable or reproducible.
  • Tunnel visioning of developers.
  • Developers prefer writing new code, don't like testing.
May suffice for "obvious" programming errors, but may not be effective for incomplete or misunderstood requirements — the author's own blind spot is exactly what caused the requirement to be misread in the first place.

Code Walkthrough

group · informal

Group-oriented, as against desk checking — brings in multiple perspectives. Less formal than inspection.

Formal Inspection / Fagan Inspection

group · highly formal

A group-oriented activity, highly formal and structured, with specific roles and requiring thorough preparation. Named after Michael Fagan (IBM).

The four roles (mnemonic: A-M-I-S)
  • Author — author of the work product, makes required material available to reviewers, fixes reported defects.
  • Moderator — controls the meeting(s).
  • Inspectors (reviewers) — prepare by reading required documents, take part in meetings and report defects.
  • Scribe — takes notes during the meeting, assigned in advance by turns, documents minutes and circulates them.
Documents typically circulated
Program code Design / program specs SRS (if needed) Applicable standards Checklists
"Never leave home without it!" — the code review checklist aids organizational learning by indicating what to look for, and should be kept current as the team learns.
The three meetings
Preliminary meeting (optional)
Author explains their perspective, makes available the necessary documents, and highlights concern areas for which review comments are sought.
Defect Logging Meeting
Everyone comes prepared. Moderator goes through the code sequentially; each reviewer raises comments. Comments are categorized: "defect" / "observation," "major" / "minor," "systemic" / "mis-execution." Scribe documents and circulates all findings.
Follow-up meeting (optional) — author fixes defects; if required, a follow-up meeting verifies completeness of the fixes.
Advantages
  • Thorough, when prepared well.
  • Brings in multiple perspectives.
  • Found to be very effective.
Disadvantages
  • Logistically difficult.
  • Time consuming.
  • May not be possible to exhaustively go through the entire code.

Combining Methods & Static Analysis Tools

practical mix
Prioritizing programs

High priority / important code → formal inspection. Medium priority → walkthrough. Low priority → desk checking. Teams also decide between 100% coverage vs. partial coverage.

What static analysis tools catch
  • Unreachable code (e.g. from goto misuse)
  • Variables declared but not used
  • Mismatch in definition vs. assignment of variables
  • Illegal or error-prone type-casting
  • Non-portable / architecture-dependent constructs
  • Memory allocated with no matching free (leaks)
  • Cyclomatic complexity calculation
  • Extension of compilers — lint, compiler-flag-driven checking
§ 04 — STRUCTURAL TESTING

Running the executable against test data

Structural testing is done by running the executable on a machine: running the product against predefined test cases and comparing results against expected results, designing test cases and test data to exercise certain portions of code. It has three types: unit / code functional testing, code coverage testing, and code complexity testing.

Unit / Code Functional Testing

Initial quick checks by the developer. Removes "obvious" errors before more expensive checks. Involves building "debug versions" and running through an IDE. ("Debugging" or "testing"? Who cares!)

Code Coverage Testing

Exercises different parts of code and maps them to required functionality. Finds the percentage of code covered by "instrumentation" — a rebuild of the product, linked with special libraries ("plugged in"), that can monitor what parts of the code are covered. Helps identify critical portions of code executed often.

Other uses of code coverage methods: performance analysis and optimization · resource usage analysis · checking of critical sections · identifying memory leaks · dynamically generated code (e.g. dynamic URL generation and security checking).
🧱
Memory hook — programming constructs
"Programs are always written in sequential format."
Every construct reduces to: sequential instructions → two-way decisions (if–then–else) → multi-way decisions (switch) → loops (while/do, for, repeat/until).
Testing sequential instructions

Generate test data that makes the program enter the sequential block and go all the way through it (watch for multiple entry points in non-structured programming). Statement coverage as a metric:

Statement coverage = (# statements exercised) / (Total # statements)
Testing IF–THEN–ELSE

Have data to test the THEN part and data to test the ELSE part.

Total = 0; /* set total to zero */
if (code == "M") {
    stmt1; stmt2; stmt3; stmt4;
    stmt5; stmt6; stmt7;
}
else percent = value/Total*100; /* divide by zero */
If a test suite only ever enters the THEN branch, statement coverage looks fine — but the ELSE branch's divide-by-zero never gets exercised.
Testing a Loop

There should be test cases that: skip the loop completely; exercise the loop between once and the maximum number of times; try covering the loop around the "boundary" of n.

Exhaustive coverage of all statements in a program is impossible for all practical purposes.
§ 05 — CODE COVERAGE TYPES

Statement, path, condition, function

One running example threads through the rest of this chapter — memorize its shape and every coverage criterion becomes a variation on the same question.

The foo() function (Figure 4.1)

the running example
void foo(int a, int b, int x)
{
    if (a>1 && b==0) {
        x = x/a;
    }
    if (a==2 || x>1) {
        x = x+1;
    }
}
a A>1 AND B=0 Y c X=X/A N b A=2 OR X>1 Y e X=X+1 N d exit
Edges labeled a·b·c·d·e — exactly as in the source flowchart
PathInputOutput
aceA=2, B=0, X=4X=3
abdA=0, B=0, X=0X=0
acdA=3, B=0, X=3X=1
abeA=2, B=1, X=1X=2
A path name is the sequence of decision outcomes taken (e.g. abd = false branch of decision 1, then false branch of decision 2) — not one fixed set of inputs. Many different input combinations can trigger the same path.

Statement Coverage

weakest criterion

A set of test cases that traverses every statement at least once. Statement coverage = (# statements exercised) / (Total # of statements).

Path ace alone provides full statement coverage of foo(): test case (A=2, B=0, X=4) → expected output X=3.
This criterion is poor. Even a very high level of statement coverage does not mean the program is defect-free. Undetected errors with just ace:
  1. Maybe the first condition should be an OR rather than an AND.
  2. Maybe the second condition should be X>0 rather than X>1.
  3. Path abd (A=1, B=1, X=1) leaves X unchanged — if that's an error, statement coverage never caught it.

Path Coverage

stronger representation

Statement coverage may not indicate "true coverage." Path coverage provides a better representation. Path coverage = (# paths exercised) / (Total # of paths in the program).

mm<1 || mm>12 A True Invalid Date B False mm==2 D False C True leapyear (yyyy) E True Days[2]=29 F False Days[2]=28 dd<Days[mm] || dd>Days[mm] G True Invalid Date H False Valid Date
Date-validation flow graph — decision nodes labeled A–H, edges labeled Y/N
Each Y/N branch through this graph is a distinct path. Statement coverage could pass while entire combinations — e.g. February in a leap year that then fails the day-bound check — are never exercised together.

Condition Coverage

refines path coverage

A further refinement of path coverage. Makes sure each constituent condition in a boolean expression is covered — protects against compiler optimizations (e.g. short-circuit evaluation hiding an untested sub-condition).

Condition coverage = (# conditions covered) / (# conditions in the program)
Loop exercise: DO K=0 to 50 WHILE (J+K<QUEST) has two conditions — K<=50 and J+K<QUEST. Condition coverage needs 4 test cases: K<=50, K>50, J+K<QUEST, J+K>=QUEST.

Function Coverage

highest abstraction

Finds how many functions are covered by test cases. A higher level of abstraction — hence it's possible to achieve 100% coverage. More "logical" than the other coverage types.

  • Can be derived from an RTM (Requirements Traceability Matrix).
  • Easy to prioritize since based on requirements.
  • Leads more naturally to black-box tests.
  • Can also be a natural predecessor to performance testing.
§ 06 — WHITE-BOX TESTING TECHNIQUES

Five criteria, same code, five different guarantees

Statement, decision, condition, decision/condition, and multiple-condition coverage — all applied to the same foo() function, each catching a bug the last one missed.

White-box testing is concerned with the degree to which test cases exercise or cover the logic of the source code. The ultimate white-box test would execute every path — an unrealistic goal for any program with loops. Backing away from "every path," a more reasonable goal is to execute every statement at least once — which is exactly where the coverage ladder starts.

Extra memorization aid — the coverage strength ladder
Statement
Weakest. Every statement runs once. Misses untaken branches entirely (an ELSE that never fires).
Decision (Branch)
Stronger. Every decision hits both True and False. Usually implies statement coverage — but can still miss individual condition values inside a compound expression.
Condition
Different, not strictly stronger. Every individual condition takes True and False at least once — but does not guarantee every decision outcome is hit.
Decision/Condition
Union of the two. Every condition outcome and every decision outcome, guaranteed together.
Multiple-Condition
Strongest of the five. Every possible combination of condition outcomes per decision. Satisfies condition-, decision-, and decision/condition-coverage — but still does not guarantee full path coverage.

Decision Coverage (Branch Coverage)

criterion 2

A stronger logic-coverage criterion than statement coverage. Write enough test cases to cover each decision with both the true and false outcomes at least once. In case of multiple choices in a decision (e.g. a switch statement), cover all choices at least once. Some languages have multiple entry points for a module or program (e.g. PL/1) — the precise definition is to exercise every possible outcome of all decisions at least once and invoke each point of entry at least once.

Decision coverage provides statement coverage in most circumstances — every statement must be executed if every branch direction is executed. Exceptions: programs with no decisions, and programs/subroutines with multiple entry points (a statement might execute only if the program is entered at a particular entry point).
Set A (red)
aceA=2, B=0, X=4X=3
abdA=1, B=1, X=1X=1
Set B (yellow)
acdA=3, B=0, X=3X=1
abeA=2, B=1, X=1X=2
Either set satisfies decision coverage. Problem: only Set A contains path abd, the only path that catches an "X must be changed" error — so there's only a 50% chance of picking the set that catches it. And if the second decision were wrong (should be X<1 instead of X>1), Set B wouldn't detect the mistake at all. We need a better criterion.

Condition Coverage — applied to foo()

criterion 3

Write enough test cases so each condition in each decision takes on all possible values at least once, and each point of entry is invoked at least once. A stronger logic-coverage test than decision coverage.

Four conditions in foo(): A>1, B==0 (B==0 in C/Java), A==2 (A==2 in C/Java), X>1. Test cases must cover: A>1 / A<=1 — B==0 / B<>0 — A==2 / A<>2 — X>1 / X<=1.

When we pick a value for a variable, it may satisfy more than one condition requirement at once. Just two test cases can cover all eight requirements: A=2, B=0, X=4 (path ace) and A=1, B=1, X=1 (path abd).

⚠ The trap: those same two test cases fail decision coverage of the OR

Decomposing A=2 OR X>1 into simple predicates IF(A=2) then IF(X>1) reveals: the false outcome of "B==0" and the true outcome of "X>1" are both missed by ace + abd. Condition coverage on the whole expression does not guarantee condition coverage on each simple predicate once it's decomposed.

A different pair — A=2, B=4, X=4 (path abe) and A=0, B=0, X=1 (path abd) — also covers all four conditions' true/false values, but path c (and the statement on it) is never executed by this set. So: condition coverage does not guarantee decision coverage, and therefore no guarantee of path or statement coverage either.

Decision/Condition Coverage

criterion 4 — the fix

The solution to condition coverage's gap: select test cases such that every condition outcome, every decision outcome, and every point of entry are exercised at least once.

Multiple-Condition Coverage

criterion 5 — the strongest

Write sufficient test cases so that all possible combinations of condition outcomes in each decision, and all points of entry, are exercised at least once. Multiple condition coverage satisfies condition-, decision-, and decision/condition-coverage criteria simultaneously.

#Combination#Combination
1A>1 and B=05A=2 and X>1
2A>1 and B<>06A=2 and X<=1
3A<=1 and B=07A<>2 and X>1
4A<=1 and B<>08A<>2 and X<=1
Four test cases cover all eight: A=2,B=0,X=4 → covers 1,5 · A=2,B=1,X=1 → covers 2,6 · A=1,B=0,X=2 → covers 3,7 · A=1,B=1,X=1 → covers 4,8.
Multiple-condition coverage does not guarantee path coverage — this exact set of test cases misses path acd. That there are 4 test cases and 4 paths in this program is pure coincidence — there is no inherent relationship between the number of paths and the number of test cases.
Worked example — TABSIZE / NOTFOUND

Four situations to test: (1) I<=TABSIZE and NOTFOUND true; (2) I<=TABSIZE and NOTFOUND false (found before end of table); (3) I>TABSIZE and NOTFOUND true (hit end without finding); (4) I>TABSIZE and NOTFOUND false (entry is the last one in the table).

Worked example — triple-AND decision
if (x==y && length(z)==0 && FLAG)
    j=1;
else
    i=1;

Three boolean conditions → 2³ = 8 test cases for multiple-condition coverage (x==y, length(z)==0, FLAG each T/F, all combined).

Summary rule: for programs with only one condition per decision, the minimum test criterion is enough test cases to (1) evoke all outcomes of each decision at least once, and (2) invoke each point of entry at least once (ensuring every statement executes). For programs with decisions having multiple conditions, the minimum criterion is enough test cases to (1) evoke all possible combinations of condition outcomes in each decision, and (2) invoke all points of entry at least once. ("Possible" — because some combinations may be impossible to create.)
§ 07 — CODE COMPLEXITY

Cyclomatic complexity & independent paths

Two open questions drive this: which of the paths are independent (if paths aren't independent, we may minimize the number of tests needed)? And is there an upper bound on the number of tests needed to ensure every statement executes at least once? Cyclomatic complexity answers both — it's an indication of how many "independent paths" exist in a program.

🔢
Memory hook — the two equivalent formulas
"Predicates Plus One" = "Edges minus Nodes plus Two"
CC = (# of predicate nodes) + 1  ≡  CC = E − N + 2 (E = edges, N = nodes). They always agree — use whichever is easier to count from the diagram you have.
Steps to determine cyclomatic complexity
  1. Start with a conventional flow chart.
  2. Identify the "decision points" — each one is a predicate.
  3. Convert "complex predicates" to "simple predicates."
  4. If there are loops, convert the loop conditions to simple predicates too.
  5. Combine all sequential statements into a single node in the flow graph.
  6. When sequential statements are followed by a simple predicate, combine the statements and the predicate check into one node with two edges emanating out — nodes with two emanating edges are called predicate nodes.
  7. Make sure all edges terminate in some node — add a node to represent all statements at the end of the program.
Splitting a complex predicate
IF (A or B) α β IF (A) IF (B) α β
(a) One predicate with a Boolean OR → (b) two chained simple predicates
Case (i): no decision node
N=2, E=1, P=0 → CC = E−N+2 = 1 and CC = P+1 = 1. # of independent paths = 1 (there's only one way through).
Case (ii): adding one decision node
N=4, E=4, P=1 → CC = E−N+2 = 2 and CC = P+1 = 2. # of independent paths = 2. Every decision node introduced adds exactly one new path.

Independent Paths & Basis Sets

applying CC

An independent path is a path in the flow graph that has not been traversed before in other paths. A set of independent paths that together cover all the edges is called a basis set. Find the basis set, then write test cases to execute every path in it — that's exactly how many tests you minimally need.

Meaning & interpretation — memorize this table
Cyclomatic ComplexityWhat it means
1 – 10Well-written code, testability is high, cost/effort to maintain is low.
10 – 20Moderately complex, testability is medium, cost/effort to maintain is medium.
20 – 40Very complex, testability is low, cost/effort to maintain is high.
> 40Not testable — any amount of money/effort may not be enough.
§ 08 — CHALLENGES

Where white-box testing breaks down in practice

⏱️

"Not finding time"

Developers routinely report not finding time for testing under delivery pressure.

🙈

Blind spots

Developers develop blind spots for their own defects — the same misunderstanding that caused the bug also hides it.

🎯

Coverage ≠ realism

Fully covered code may not correspond to realistic user scenarios — 100% coverage is not the same as "correct."

§ 09 — COMMON MISTAKES

Where exam answers actually go wrong

Every one of these has shown up as a graded confusion — drill them until the wrong answer stops sounding plausible.

1. "100% statement coverage means the code is well tested."

✗ WRONG: Statement coverage alone is a strong quality signal.
✓ RIGHT: Statement coverage is the weakest criterion. In the Total=0; if(code=="M")...else percent=value/Total*100; example, a test suite that only ever hits the IF branch gets full statement coverage while the divide-by-zero in ELSE never runs.

2. "Decision coverage covers all individual conditions."

✗ WRONG: Hitting both True and False on a compound decision means every condition inside it was tested both ways.
✓ RIGHT: A compound decision can be True/False without every individual condition inside it taking both values — short-circuit evaluation can mask a sub-condition entirely. That's exactly why condition coverage exists as a separate, stronger criterion.

3. "Since condition coverage is 'stronger,' it guarantees decision coverage too."

✗ WRONG: Condition coverage implies decision coverage implies statement coverage, in a clean chain.
✓ RIGHT: They're not nested that way. The A=2,B=4,X=4 / A=0,B=0,X=1 pair covers all four individual conditions but never executes path c — so condition coverage does not guarantee decision, path, or statement coverage. You need Decision/Condition coverage to get both guarantees at once.

4. "Multiple-condition coverage = full path coverage."

✗ WRONG: The strongest coverage criterion in this chapter must also guarantee every path is executed.
✓ RIGHT: The 4-test-case set for foo() covers all 8 condition combinations but still misses path acd. There is no inherent relationship between the number of test cases and the number of paths — matching counts (4 tests, 4 paths) is coincidence, not causation.

5. Mixing up the cyclomatic complexity formulas or miscounting predicates.

✗ WRONG: Treating a compound condition like (A or B) as one predicate node, or forgetting the "+2" / "+1" term.
✓ RIGHT: CC = E − N + 2 = P + 1. Complex predicates must first be split into simple predicates — each becomes its own predicate node — before counting. Undercounting compound conditions understates the true complexity.

6. Treating desk checking, walkthrough, and Fagan inspection as interchangeable.

✗ WRONG: "They're all just manual code review — pick any name."
✓ RIGHT: Desk checking = solo, author only, no log. Walkthrough = group, informal. Fagan/formal inspection = group, highly formal, defined roles (Author, Moderator, Inspectors, Scribe) and structured meetings (Preliminary → Defect Logging → Follow-up).

7. "White-box testing means running the code."

✗ WRONG: All white-box testing involves execution.
✓ RIGHT: White-box testing splits into Static testing (no execution — humans or tools reading source) and Structural testing (executes the compiled program against test cases). Code coverage and cyclomatic complexity live under different branches — coverage is structural, complexity calculation is often a static-tool feature.

8. Assuming a path label maps to one fixed set of input values.

✗ WRONG: "Path abd is always A=0,B=0,X=0" (or always A=1,B=1,X=1 — picking whichever slide you saw first).
✓ RIGHT: A path is the sequence of decision outcomes taken (here: false on decision 1, then false on decision 2) — many different inputs can trigger the same path, which is exactly why the deck uses abd with different concrete values in different examples.
§ 10 — CHEAT SHEET

Every technique, one scannable grid

TechniqueFormula / RuleGuaranteesKey weakness
Desk checkingAuthor self-review, no formalismCatches "obvious" errorsNot scalable, tunnel vision
Code walkthroughGroup, informalMultiple perspectivesLess structured than inspection
Fagan / formal inspectionGroup, roles (Author/Moderator/Inspectors/Scribe)Very effective, thoroughLogistically hard, time-consuming
Statement coverage# stmts exercised / total stmtsEvery line runs onceMisses whole untaken branches
Path coverage# paths exercised / total pathsBetter representation than statementsExplodes with loops/branches
Decision (branch) coverageEvery decision T & F at least onceUsually implies statement coverageDoesn't guarantee condition coverage
Condition coverage# conditions covered / # conditionsEvery individual condition T & FDoesn't guarantee decision coverage
Decision/Condition coverageUnion of the two aboveBoth decision & condition outcomesStill not full path coverage
Multiple-condition coverageAll 2ⁿ combos per decisionCondition + decision + decision/conditionStill not full path coverage
Cyclomatic complexityCC = E−N+2 = P+1# of independent paths / basis set sizeMiscounted if predicates aren't simplified first
§ 11 — POP QUIZ

Click to reveal

No reload, no external libraries — just click a question to check yourself.

Q1 · Multiple choice
In foo(), running only path ace (A=2, B=0, X=4) satisfies which coverage criterion?
Statement coverage. It traverses every statement at least once, but it's a poor criterion — it can't tell you if the AND should be an OR, or if X>1 should be X>0.
Q2 · Short answer
Write the cyclomatic complexity formula in terms of edges (E) and nodes (N).
CC = E − N + 2. Equivalently, CC = (# of predicate nodes) + 1.
Q3 · Multiple choice
Which of these does condition coverage not guarantee?
Decision coverage (and therefore path/statement coverage too). A test set can hit every individual condition's true/false values while never executing a particular decision outcome — e.g. never taking path c in foo().
Q4 · Short answer
Name the four roles in a Fagan (formal) inspection.
Author, Moderator, Inspectors (reviewers), Scribe. Mnemonic: A-M-I-S.
Q5 · Multiple choice
A program measures a cyclomatic complexity of 45. This means:
Not testable — any amount of money/effort may not be enough. (CC > 40 is the worst bracket on the interpretation table.)
Q6 · Short answer
Given a program with no loops is unrealistic to path-cover exhaustively, what's the reasonable fallback goal stated in the deck?
Execute every statement at least once. ("The ultimate white-box testing is to execute every path — an unrealistic goal with loops. A reasonable goal is to execute every statement at least once.")
Q7 · Multiple choice
Which static testing type is solo, author-only, with no log or checklist maintained?
Desk checking. It relies entirely on the thoroughness of the individual author.
Q8 · True / False
Multiple-condition coverage guarantees full path coverage.
False. The 4-test-case example that covers all 8 condition combinations for foo() still misses path acd.
§ 12 — PRACTICE LAB

Exam-shaped problems, worked

Same shape of question as the graded exercises in the deck — drill until it's automatic.

1. For foo(int a, int b, int x), give one test case that achieves 100% statement coverage, and name the path it takes.
→ A=2, B=0, X=4 → expected output X=3 (path ace)
Why: this input makes both decisions evaluate True, so both the x=x/a and x=x+1 statements execute — every line runs at least once.
2. A control-flow graph has 7 edges and 6 nodes. Compute its cyclomatic complexity.
→ CC = E − N + 2 = 7 − 6 + 2 = 3
Why: direct substitution into the edge/node formula — no need to count predicate nodes separately once E and N are known.
3. A decision combines three boolean sub-conditions with AND. How many test cases does condition coverage need at minimum, versus multiple-condition coverage?
→ Condition coverage: as few as 2. Multiple-condition coverage: up to 2³ = 8.
Why: condition coverage only needs each sub-condition to be True once and False once total (often combinable into 2 well-chosen test cases); multiple-condition coverage needs every combination of the three sub-conditions' truth values.
4. A divide-by-zero bug hides in an ELSE branch that a statement-coverage-only test suite never enters. Which coverage criterion is the minimum needed to force that branch to run?
→ Decision (branch) coverage
Why: decision coverage requires both the True and False outcome of every decision to be exercised, which forces the ELSE branch to run at least once.
5. In a Fagan inspection, the author explains their perspective, makes documents available, and highlights concern areas before the main review — which meeting is this?
→ Preliminary meeting (optional)
Why: that's exactly the definition given for the preliminary meeting, distinct from the Defect Logging Meeting where reviewers actually raise and categorize defects.