03 Testing Fundamentals: Coverage Concepts Quiz
December 2025 (6178 Words, 35 Minutes)
New: Interactive Quiz Available!
Want to track your progress and get instant feedback? Try our new interactive version with progress tracking, immediate explanations, and score calculation.
Instructions
This quiz tests your understanding of code coverage concepts from Lectures 6 and 7.
Preparation: Read First
Before attempting this quiz, study the following lecture sections:
From Chapter 03 (TDD and CI): TDD and CI:
- Part 2: The Coverage Problem - Why we need coverage
- Part 3: Setting Up Coverage Reporting - pytest-cov basics
- Part 4: Integrating Coverage into CI - Thresholds and automation
From Chapter 03 (Testing Theory and Coverage): Testing Theory & Coverage:
- Section 3: The Testing Theory - Program, Model, Test Suite, Coverage Criterion
- Section 4: Code Coverage (C0 and C1) - Statement vs Branch coverage, Subsumption
Focus areas: Definitions, subsumption hierarchy, coverage limitations
Why Take This Quiz?
For Your Learning:
- Self-Assessment: Identify areas where you have strong understanding and topics that need review
- Exam Preparation: The quiz format and difficulty mirror what you can expect in the final exam
- Immediate Feedback: Get instant feedback on your answers to reinforce correct understanding
- Active Recall: Testing yourself is one of the most effective learning techniques
Guidelines:
- Each question has 4 options with exactly one correct answer
- Try to answer without referring to the lecture materials first
- Focus on understanding concepts, not memorizing definitions
- Click “Show Answer” to see the explanation after attempting each question
Section A: Definitions and Basics
Question 1: What is Statement Coverage?
Statement coverage (C0) measures:
A) The percentage of functions that have at least one test
B) The percentage of executable code statements executed by tests
C) The number of test cases divided by lines of code
D) The percentage of branches that return True
Show Answer
Correct Answer: B
Statement coverage (C0) measures the percentage of executable statements in your code that are executed during testing.
Formula:
\(\text{C0} = \frac{\text{Executed Statements}}{\text{Total Statements}} \times 100\%\)
Example:
def example(x):
if x > 0: # Statement 1
print("pos") # Statement 2
return x # Statement 3
If you test with example(5):
- Statements executed: 1, 2, 3 (all 3)
- C0 = 3/3 = 100%
If you test with example(-5):
- Statements executed: 1, 3 (statement 2 skipped)
- C0 = 2/3 = 67%
Why other options are wrong:
- A: That would be “function coverage,” not statement coverage
- C: Coverage is about execution, not a simple ratio of tests to code
- D: This describes branch outcomes, not statement execution
Question 2: What is Branch Coverage?
Branch coverage (C1) measures:
A) The percentage of code branches (True/False outcomes) executed by tests
B) The number of if-statements in the code
C) The percentage of functions with return statements
D) How many times each line of code is executed
Show Answer
Correct Answer: A
Branch coverage (C1) measures the percentage of decision outcomes (True/False branches) that are executed during testing.
Formula:
\(\text{C1} = \frac{\text{Executed Branches}}{\text{Total Branches}} \times 100\%\)
Example:
def example(x):
if x > 0: # Decision with 2 branches: True, False
return "pos" # True branch
return "neg" # False branch (implicit else)
If you test with example(5):
- True branch: Executed
- False branch: NOT executed
- C1 = 1/2 = 50%
To get 100% C1, you need BOTH:
example(5)→ True branchexample(-5)→ False branch
Why other options are wrong:
- B: Counting if-statements isn’t coverage; it’s a code metric
- C: This isn’t a standard coverage measure
- D: This describes “execution count,” not branch coverage
Question 3: What is a Coverage Criterion?
A coverage criterion is:
A) A tool that measures how fast tests run
B) A rule defining what must be tested to consider a test suite adequate
C) The minimum number of tests required per function
D) A scoring rubric for grading student code
Show Answer
Correct Answer: B
A coverage criterion is a formal rule that defines what elements of a program must be exercised (covered) by a test suite for that suite to be considered “adequate” according to that criterion.
Examples of coverage criteria:
- Statement Coverage (C0): Every statement must be executed at least once
- Branch Coverage (C1): Every branch outcome must be executed at least once
- Path Coverage: Every possible path through the code must be executed
- Condition Coverage: Every boolean sub-expression must be True and False
Why this matters:
Different criteria have different strengths (fault detection) and costs (number of tests needed). Choosing the right criterion depends on:
- Risk level of the code
- Available testing resources
- Required confidence level
Why other options are wrong:
- A: That’s a performance metric, not a coverage criterion
- C: Coverage is about what’s tested, not a fixed count
- D: Coverage criteria are for test adequacy, not grading
Question 4: What Does “Subsumption” Mean in Testing?
When we say “C1 subsumes C0,” we mean:
A) C1 tests run faster than C0 tests
B) Achieving 100% C1 guarantees 100% C0 automatically
C) C0 is more thorough than C1
D) C1 requires fewer tests than C0
Show Answer
Correct Answer: B
Subsumption means that one coverage criterion is “stronger” than another. If criterion A subsumes criterion B, then achieving 100% coverage under A automatically guarantees 100% coverage under B.
C1 subsumes C0 because:
To cover both branches of a decision:
if condition:
statement_A # True branch
else:
statement_B # False branch
- You MUST execute
statement_A(to cover True branch) - You MUST execute
statement_B(to cover False branch) - Therefore, both statements are covered
The reverse is NOT true:
You can have 100% C0 without 100% C1:
def risky(x, logging=True):
if logging:
log_event(x) # Always executed if logging=True
return process(x) # Always executed
Testing only with logging=True gives:
- C0: 100% (all statements executed)
- C1: 50% (only True branch of
if loggingtested)
Why other options are wrong:
- A: Subsumption is about coverage, not speed
- C: The opposite is true; C1 is more thorough
- D: C1 typically requires MORE tests (must cover both branches)
Question 5: What is Test Adequacy?
A test suite is “adequate” according to a coverage criterion when:
A) All tests pass without errors
B) The test suite achieves 100% coverage according to that criterion
C) At least 10 tests exist for each module
D) Tests run in under 1 second
Show Answer
Correct Answer: B
Test adequacy is a property of a test suite relative to a specific coverage criterion. A test suite is adequate if it achieves 100% coverage according to the chosen criterion.
Examples:
- C0-adequate: Every statement is executed by at least one test
- C1-adequate: Every branch outcome is executed by at least one test
Important distinction:
- Adequate means “meets the criterion’s requirements”
- Adequate does NOT mean “tests are correct” or “code is bug-free”
A test suite can be C0-adequate while still:
- Having weak assertions
- Missing edge cases
- Failing to detect actual bugs
Why other options are wrong:
- A: Tests passing is about correctness, not adequacy
- C: Adequacy isn’t about count; it’s about coverage
- D: Speed is a performance concern, not adequacy
Section B: Understanding and Calculation
Question 6: Why Does C1 Subsume C0?
Consider this code:
def check(value):
if value > 0:
return "positive"
else:
return "negative"
Why does achieving 100% C1 automatically give 100% C0?
A) Because C1 counts more statements than C0
B) Because covering both branches requires executing all statements in those branches
C) Because C1 tests are longer than C0 tests
D) Because branch coverage is calculated after statement coverage
Show Answer
Correct Answer: B
To achieve 100% C1 on this code, you must cover:
- True branch (
value > 0is True) → Executesreturn "positive" - False branch (
value > 0is False) → Executesreturn "negative"
By covering both branches, you’ve necessarily executed:
- Line 2:
if value > 0:(the condition itself) - Line 3:
return "positive"(True branch statement) - Line 5:
return "negative"(False branch statement)
All 3 executable statements are covered, so C0 = 100%.
Visual proof:
| Test | Branch Covered | Statements Executed |
|---|---|---|
check(5) |
True | Lines 2, 3 |
check(-5) |
False | Lines 2, 5 |
| Combined | 100% C1 | All statements (100% C0) |
Why other options are wrong:
- A: C1 doesn’t “count” statements; it counts branch outcomes
- C: Test length isn’t related to subsumption
- D: The order of calculation doesn’t affect the relationship
Question 7: Calculate Statement Coverage
Given this code and test:
def categorize(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
# Test:
def test_high_score():
assert categorize(95) == "A"
What is the statement coverage (C0)?
A) 25%
B) 40%
C) 50%
D) 100%
Try It Yourself
You can verify your answer by running pytest-cov! Create these files:
src/grading.py:
def categorize(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
tests/test_grading.py:
from src.grading import categorize
def test_high_score():
assert categorize(95) == "A"
Run coverage:
uv run pytest tests/ --cov=src --cov-report=term-missing
Prerequisites: Python 3.12+, uv package manager, pytest and pytest-cov installed (uv add pytest pytest-cov).
Show Answer
Correct Answer: B
Let’s count the executable statements:
def categorize(score):
if score >= 90: # Statement 1 (condition check)
return "A" # Statement 2 (executed)
elif score >= 80: # Statement 3 (NOT executed - short-circuit)
return "B" # Statement 4 (NOT executed)
elif score >= 70: # Statement 5 (NOT executed)
return "C" # Statement 6 (NOT executed)
else:
return "F" # Statement 7 (NOT executed)
With categorize(95):
- Statement 1: Executed (condition is True)
- Statement 2: Executed (returns “A”)
- Statements 3-7: NOT executed (function returns early)
Calculation:
- Executed: 2 statements
- Total: 5 statements (the 4 returns + the function’s entry/first condition)
- C0 = 2/5 = 40%
Note: Exact counts may vary depending on how your coverage tool counts statements (some count if and elif separately, some don’t). The key insight is that only a small portion of the code is executed.
Why other options are wrong:
- A (25%): Too low; we executed more than 1 out of 4
- C (50%): We didn’t execute half the statements
- D (100%): We clearly skipped the B, C, and F branches
Question 8: Calculate Branch Coverage
Using the same code from Question 7:
def categorize(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
# Tests:
def test_scores():
assert categorize(95) == "A"
assert categorize(85) == "B"
What is the branch coverage (C1)?
A) 25%
B) 50%
C) 75%
D) 100%
Try It Yourself
Verify your answer using pytest-cov with branch coverage enabled:
tests/test_grading.py:
from src.grading import categorize
def test_scores():
assert categorize(95) == "A"
assert categorize(85) == "B"
Run with branch coverage:
uv run pytest tests/ --cov=src --cov-branch --cov-report=term-missing
The --cov-branch flag enables branch coverage reporting. Look for the “Branch” and “BrPart” columns in the output.
Show Answer
Correct Answer: B
Let’s identify all branches:
if score >= 90: # Branch 1 (True), Branch 2 (False)
return "A"
elif score >= 80: # Branch 3 (True), Branch 4 (False)
return "B"
elif score >= 70: # Branch 5 (True), Branch 6 (False)
return "C"
else:
return "F"
Total branches: 6 (each condition has True and False outcomes)
With our tests:
| Test | score >= 90 | score >= 80 | score >= 70 |
|---|---|---|---|
categorize(95) |
True (Branch 1) | - | - |
categorize(85) |
False (Branch 2) | True (Branch 3) | - |
Branches covered: 1, 2, 3 = 3 branches Branches NOT covered: 4, 5, 6 (need scores like 75 and 50)
Calculation:
C1 = 3/6 = 50%
To achieve 100% C1, we’d need:
categorize(95)→ A (covers score >= 90 True)categorize(85)→ B (covers score >= 90 False, score >= 80 True)categorize(75)→ C (covers score >= 80 False, score >= 70 True)categorize(50)→ F (covers score >= 70 False)
Question 9: Interpret Coverage Report
Given this pytest-cov output:
Name Stmts Miss Cover Missing
-----------------------------------------------
src/utils.py 24 6 75% 18-20, 35-37
-----------------------------------------------
What does “Missing: 18-20, 35-37” tell you?
A) Lines 18-20 and 35-37 have syntax errors
B) Lines 18-20 and 35-37 were not executed by any test
C) Lines 18-20 and 35-37 should be deleted
D) Lines 18-20 and 35-37 contain the most important code
Show Answer
Correct Answer: B
The “Missing” column shows line numbers that were not executed by any test in your test suite.
What this means:
- Lines 18, 19, 20: Not covered by tests
- Lines 35, 36, 37: Not covered by tests
- These lines represent untested code paths
What to do about it:
- Look at the code on those lines
- Understand why they weren’t executed:
- Is it a conditional branch that wasn’t triggered?
- Is it error handling code?
- Is it dead code that should be removed?
- Add tests that execute those lines (if they’re valid code)
Example scenario:
# Line 18-20 might be:
if special_case:
handle_special()
return early_result
# Your tests never triggered special_case = True
Why other options are wrong:
- A: Coverage tools don’t detect syntax errors; they measure execution
- C: Missing lines aren’t necessarily bad; they just need tests
- D: The importance of code isn’t related to whether it’s tested
Question 10: Match Report to Code
Given this code:
1
2
3
4
5
6
7
8
def validate(value):
if value is None:
return "Error"
if value < 0:
return "Negative"
if value == 0:
return "Zero"
return "Positive"
And this coverage report:
Missing: 3, 7
Which conditions were NEVER False during testing?
A) value is None and value < 0
B) value is None and value == 0
C) value < 0 and value == 0
D) All conditions were tested as both True and False
Show Answer
Correct Answer: B
Let’s analyze what “Missing: 3, 7” means:
- Line 3 missing:
return "Error"was never executed- This means
value is Nonewas never True - So
value is Nonewas always False
- This means
- Line 7 missing:
return "Zero"was never executed- This means
value == 0was never True - So
value == 0was always False
- This means
What was likely tested:
validate(5)→ Positive (lines 2, 4, 6, 8 executed)validate(-3)→ Negative (lines 2, 4, 5 executed)
What was NOT tested:
validate(None)→ Would execute line 3validate(0)→ Would execute line 7
Why other options are wrong:
- A: Line 5 (
return "Negative") is NOT missing, sovalue < 0was True at some point - C: Line 5 is NOT missing, so
value < 0was covered - D: Lines 3 and 7 are missing, so not all conditions were fully tested
Section C: Limitations of Coverage
Question 11: Why Doesn’t 100% Coverage Guarantee Bug-Free Code?
A test suite achieves 100% statement coverage. This means:
A) The code is definitely correct and production-ready
B) All possible inputs have been tested
C) Every statement was executed, but the tests might have weak or missing assertions
D) The code has no bugs
Show Answer
Correct Answer: C
100% coverage means every statement was executed, but it says nothing about:
- Whether assertions verify correct behavior
- Whether all important inputs were tested
- Whether the logic is actually correct
Example of 100% coverage with no bug detection:
def divide(a, b):
return a / b # Bug: doesn't handle b=0
def test_divide():
result = divide(10, 2)
assert result is not None # Weak assertion! Doesn't check value
This achieves 100% coverage but:
- Doesn’t verify the actual result (should be 5)
- Doesn’t test b=0 (which would crash)
- Provides false confidence
What coverage DOES tell you:
- Which code was not executed at all (definitely not tested)
- Gaps in your test suite
What coverage does NOT tell you:
- Whether tests actually verify correctness
- Whether edge cases are handled
- Whether the code is bug-free
Why other options are wrong:
- A: Correctness requires proper assertions, not just execution
- B: You can achieve 100% coverage with very few inputs
- D: Coverage measures execution, not correctness
Question 12: Bad Test with High Coverage
Consider this code and test:
def calculate_total(items, discount_percent):
total = sum(items)
if discount_percent > 0:
discount = total * (discount_percent / 100)
total = total - discount
return total
def test_calculate_total():
result = calculate_total([10, 20, 30], 10)
# What's wrong with this test?
assert result > 0
What’s the problem with this test?
A) It doesn’t achieve 100% coverage
B) It uses the wrong assertion syntax
C) The assertion is too weak - it doesn’t verify the correct value
D) The test name is not descriptive enough
Show Answer
Correct Answer: C
The test achieves high coverage by executing:
total = sum(items)→ 60if discount_percent > 0:→ Truediscount = total * (discount_percent / 100)→ 6total = total - discount→ 54return total→ returns 54
But the assertion assert result > 0 is extremely weak:
- It would pass for
result = 1(wrong!) - It would pass for
result = 100000(wrong!) - It would pass for
result = 54(correct)
A proper test should verify the exact expected value:
def test_calculate_total_with_discount():
# Arrange
items = [10, 20, 30]
discount_percent = 10
# Act
result = calculate_total(items, discount_percent)
# Assert - verify the exact expected value
expected = 54 # (10+20+30) - 10% = 60 - 6 = 54
assert result == expected
Key insight:
Coverage tells you the code ran, but only good assertions tell you the code worked correctly.
Why other options are wrong:
- A: The test likely does achieve good coverage (all lines executed)
- B: The syntax is valid Python
- D: While true, the weak assertion is the critical problem
Question 13: What Can Coverage NOT Detect?
Which of the following bugs would 100% statement coverage likely MISS?
A) A missing import statement
B) An incorrect calculation formula
C) A syntax error in the code
D) An undefined variable
Show Answer
Correct Answer: B
An incorrect calculation formula might still execute perfectly, achieving 100% coverage, while producing wrong results.
Example:
def calculate_area(radius):
return 3.14 * radius * radius # Bug: should use math.pi
def test_area():
result = calculate_area(10)
assert result is not None # Passes! But result is slightly wrong
This achieves 100% coverage but:
- The formula uses
3.14instead ofmath.pi - The result is approximately 314 instead of 314.159…
- A weak assertion won’t catch this
What coverage CAN detect (indirectly):
- A (missing import): Would crash when that module is used
- C (syntax error): Python won’t run at all
- D (undefined variable): Would raise NameError when executed
Key insight:
Coverage detects crashes (code that fails to run) but not logical errors (code that runs but produces wrong output).
This is why you need:
- Good coverage (code is executed)
- Strong assertions (behavior is verified)
- Edge case testing (boundary conditions checked)
Question 14: When is 70% Coverage Acceptable?
In which situation might 70% coverage be perfectly acceptable?
A) Never - always aim for 100%
B) When the uncovered 30% is dead code or unreachable error handlers
C) When tests are too expensive to write
D) When the project is almost finished
Show Answer
Correct Answer: B
70% coverage can be acceptable when the uncovered code is:
- Dead code that should be removed
- Defensive error handlers for “impossible” conditions
- Platform-specific code not relevant to current environment
- Debug/logging code that’s not critical to test
Examples of acceptable uncovered code:
def process_file(path):
try:
with open(path) as f:
return f.read()
except PermissionError:
# Only happens in restricted environments
log_error("Permission denied")
return None
except Exception as e:
# Defensive catch-all, should "never" happen
log_critical(f"Unexpected: {e}")
raise
The except blocks might be uncovered if your tests only use accessible files. That’s often OK.
When 70% is NOT acceptable:
- Core business logic is uncovered
- Happy-path functionality isn’t tested
- The 30% contains critical code
Why other options are wrong:
- A: 100% isn’t always practical or meaningful
- C: Cost alone isn’t a good reason; prioritize critical code
- D: Project stage doesn’t determine acceptable coverage
Question 15: Coverage vs Correctness
Which statement best describes the relationship between coverage and correctness?
A) High coverage proves code correctness
B) Coverage measures execution; correctness requires assertions and test design
C) Low coverage proves code is incorrect
D) Coverage and correctness are the same thing
Show Answer
Correct Answer: B
Coverage and correctness are different concepts:
| Aspect | Coverage | Correctness |
|---|---|---|
| Measures | Code execution | Behavior verification |
| Tool | pytest-cov | Assertions |
| Question | “Was this code run?” | “Does this code work right?” |
| Can be automated | Yes (completely) | Partially (assertions need human design) |
High coverage + weak assertions = False confidence
def test_broken():
result = buggy_function() # Runs the code (coverage!)
assert result is not None # Doesn't check correctness
Low coverage + strong assertions = Incomplete testing
def test_one_path():
assert calculate(10) == 100 # Correct for this input
# But what about calculate(-5)? calculate(0)?
Ideal: High coverage + strong assertions + good test design
def test_positive():
assert calculate(10) == 100
def test_negative():
assert calculate(-5) == -50
def test_zero():
assert calculate(0) == 0
def test_edge_case():
assert calculate(0.001) == 0.01
Why other options are wrong:
- A: Coverage proves execution, not correctness
- C: Low coverage means untested code, not incorrect code
- D: They’re complementary but distinct concepts
Section D: Application
Question 16: Which Test Would Cover Line X?
Given this code:
1
2
3
4
5
6
7
8
9
def classify_age(age):
if age < 0:
return "Invalid"
elif age < 18:
return "Minor"
elif age < 65:
return "Adult"
else:
return "Senior"
Your coverage report shows Line 9 is missing. Which test would cover it?
A) assert classify_age(-5) == "Invalid"
B) assert classify_age(17) == "Minor"
C) assert classify_age(30) == "Adult"
D) assert classify_age(70) == "Senior"
Try It Yourself
Test your hypothesis! Create these files and run coverage:
src/age_classifier.py:
def classify_age(age):
if age < 0:
return "Invalid"
elif age < 18:
return "Minor"
elif age < 65:
return "Adult"
else:
return "Senior"
tests/test_age.py (initial tests that leave Line 9 missing):
from src.age_classifier import classify_age
def test_ages():
assert classify_age(-5) == "Invalid"
assert classify_age(17) == "Minor"
assert classify_age(30) == "Adult"
Run coverage to see Line 9 missing:
uv run pytest tests/ --cov=src --cov-report=term-missing
Then add your chosen test and run again to verify it covers Line 9!
Show Answer
Correct Answer: D
Line 9 (return "Senior") is in the else branch, which executes when:
age < 0is False (age is 0 or positive)age < 18is False (age is 18 or older)age < 65is False (age is 65 or older)
So we need age >= 65 to reach line 9.
Analysis of each option:
| Test | age | Line 3? | Line 5? | Line 7? | Line 9? |
|---|---|---|---|---|---|
| A: -5 | -5 | Yes | No | No | No |
| B: 17 | 17 | No | Yes | No | No |
| C: 30 | 30 | No | No | Yes | No |
| D: 70 | 70 | No | No | No | Yes |
Only option D covers line 9.
Why other options are wrong:
- A: Covers line 3 (age < 0 is True)
- B: Covers line 5 (age < 18 is True)
- C: Covers line 7 (age < 65 is True)
Question 17: Design Test for Uncovered Branch
Given this code and coverage report:
1
2
3
4
5
6
7
8
9
def calculate_shipping(weight, express=False):
if weight <= 0:
raise ValueError("Invalid")
base_cost = weight * 2.0
if express:
return base_cost * 1.5
return base_cost
Coverage report: Missing lines 3, 8
To cover BOTH missing lines, you need tests with which inputs?
A) weight=5, express=True only
B) weight=-1 and weight=5, express=True
C) weight=0 and weight=5, express=False
D) weight=5, express=True and weight=10, express=True
Show Answer
Correct Answer: B
Let’s trace what covers each missing line:
Line 3 (raise ValueError): Needs weight <= 0
weight = -1→ Line 2 is True → Line 3 executes
Line 8 (return base_cost * 1.5): Needs weight > 0 AND express=True
weight = 5, express = True→ Reaches line 7, line 7 is True → Line 8 executes
Analysis of options:
| Option | Covers Line 3? | Covers Line 8? |
|---|---|---|
| A | No (weight > 0) | Yes |
| B | Yes (weight = -1) | Yes (weight=5, express=True) |
| C | Yes (weight = 0) | No (express=False) |
| D | No | Yes (both are express=True) |
Only option B covers BOTH missing lines.
Why other options are wrong:
- A: Only covers line 8, not line 3
- C: Only covers line 3, not line 8
- D: Both tests have positive weight, never covers line 3
Question 18: Interpret pytest-cov Output
Given this pytest-cov output with branch coverage enabled:
Name Stmts Miss Branch BrPart Cover
----------------------------------------------------
src/validator.py 20 2 10 3 82%
----------------------------------------------------
What does “BrPart: 3” indicate?
A) 3 branches were tested
B) 3 branches are partially covered (only one outcome tested)
C) 3 branches should be deleted
D) 3 branches have errors
Show Answer
Correct Answer: B
BrPart stands for “Branch Partial” - it counts branches where only one outcome (True OR False) was tested, but not both.
Example of partial branch coverage:
def process(value, debug=True):
if debug: # Branch: tested only when debug=True
log(value)
return transform(value)
If all tests use debug=True:
- True branch: Covered (log is called)
- False branch: NOT covered (log is skipped)
- This branch is “partially covered” → contributes to BrPart
Column meanings:
- Stmts: Total statements (20)
- Miss: Statements not executed (2)
- Branch: Total branch outcomes (10)
- BrPart: Partially covered branches (3)
- Cover: Overall coverage percentage (82%)
To fix partial branches:
Add tests that trigger the opposite condition outcome.
Why other options are wrong:
- A: BrPart counts incomplete branches, not complete ones
- C: Partial coverage isn’t a reason to delete code
- D: This is a coverage metric, not an error report
Question 19: Choose Appropriate Coverage Threshold
Your team is setting up a CI pipeline for a financial transaction system. What coverage threshold is most appropriate?
A) 50% - Low threshold to avoid blocking deploys
B) 70% - Industry standard
C) 85-90% - High threshold with focus on critical paths
D) 100% - Financial systems need complete coverage
Show Answer
Correct Answer: C
For a financial transaction system, high coverage is important because:
- Bugs can cause financial loss
- Edge cases in money handling are critical
- Regulatory requirements may mandate testing
Why 85-90% instead of 100%:
- 100% is often impractical (error handlers, debug code)
- 100% can lead to testing implementation details
- Focus should be on meaningful coverage of critical paths
Best practice for critical systems:
- Set baseline threshold (85-90%)
- Require 100% on critical modules (e.g.,
transactions.py) - Allow lower coverage on non-critical utilities
- Enforce strong assertions, not just execution
Example CI configuration:
- name: Run tests with coverage
run: pytest --cov=src --cov-fail-under=85 --cov-report=term-missing
Why other options are wrong:
- A (50%): Too low for financial systems
- B (70%): Industry standard for general apps, but financial needs more
- D (100%): Impractical and can lead to gaming the metric
Question 20: CI Integration Purpose
Why integrate coverage checks into a CI/CD pipeline?
A) To automatically fix bugs in the code
B) To prevent merging code that reduces test coverage below threshold
C) To make tests run faster
D) To replace manual code review
Show Answer
Correct Answer: B
CI coverage integration serves as a quality gate that:
- Measures coverage on every pull request
- Fails the build if coverage drops below threshold
- Prevents “coverage debt” from accumulating
- Makes coverage visible to the team
How it works:
# In GitHub Actions workflow
- name: Run tests with coverage
run: uv run pytest --cov=src --cov-fail-under=80
# If coverage < 80%, the workflow fails
# PR cannot be merged until coverage is restored
Benefits:
- Automatic enforcement: No manual checking needed
- Early feedback: Developers know immediately if they need more tests
- Trend protection: Coverage can’t silently decrease
- Team visibility: Everyone sees coverage in PR checks
What CI coverage does NOT do:
- Fix bugs automatically
- Speed up tests
- Replace code review (humans still needed)
Why other options are wrong:
- A: CI measures; it doesn’t fix
- C: Coverage checks add time, not reduce it
- D: Code review catches design issues that coverage can’t
Scoring Guide
- 18-20 correct: Excellent! You have a strong grasp of coverage concepts and their practical application
- 15-17 correct: Good understanding! Review the areas you missed to solidify your knowledge
- 12-14 correct: Fair understanding. Revisit the lecture materials on C0/C1 and coverage limitations
- 9-11 correct: Review needed. Focus on the fundamentals in Sections A and B
- Below 9: Please review Lectures 6 and 7 carefully before continuing
Key Takeaways to Remember
- Statement Coverage (C0) measures percentage of statements executed
- Branch Coverage (C1) measures percentage of branch outcomes (True/False) executed
- C1 subsumes C0: 100% branch coverage guarantees 100% statement coverage
- Coverage criterion defines what makes a test suite “adequate”
- 100% coverage ≠ bug-free: Tests can execute code without verifying it
- Weak assertions are the enemy:
assert x is not Nonecatches nothing - Coverage shows gaps: “Missing” lines tell you what’s NOT tested
- Partial branches (BrPart) mean only one outcome was tested
- 70-80% is acceptable for most projects; critical systems need more
- CI integration prevents coverage regression
What’s Next?
Continue with the CFG Tracing Exercise to practice analyzing coverage visually using Control Flow Graphs.