Comprehensive systematic approach to achieving complete test coverage through structured category-based testing
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A systematic approach to comprehensive test coverage. Work through these categories in order to ensure your tests catch all failure modes, edge cases, and security issues.
Category 1: HAPPY PATH
Definition: Expected inputs produce expected outputs with no errors.
Purpose: Verify core functionality works under normal conditions.
What to test:
Valid, typical inputs
Expected return values
Expected side effects (DB writes, API calls)
Expected state changes
Example:
deftest_create_user_happy_path():
"""Test creating user with valid data succeeds."""
user_data = {
"email": "alice@example.com",
"name": "Alice",
"password": "SecurePass123!",
}
user = create_user(user_data)
# Assert expected return valueassert user.email == "alice@example.com"assert user.name == "Alice"assert user.idisnotNone# Assert expected side effectsassert db.users.count() == 1assert user.created_at isnotNone
Common mistakes:
❌ Only testing happy path (ignoring edge cases)
❌ Not verifying side effects (DB writes, logs, events)
❌ Using unrealistic inputs (test with production-like data)
Category 2: BOUNDARY VALUES
Definition: Test at the edges of valid ranges (min, max, exactly at limit, one over limit).
Purpose: Catch off-by-one errors, overflow issues, and boundary-related bugs.
What to test:
Minimum valid value
Maximum valid value
Exactly at limit (e.g., string length exactly 255 if that's the limit)
Pagination (first page, last page, page beyond last)
Category 3: EMPTY / NULL / ZERO
Definition: Test with absent, null, zero, or empty values for each nullable input.
Purpose: Catch null pointer exceptions, division by zero, and missing data handling bugs.
What to test:
None / null / undefined for nullable fields
Empty strings ("")
Empty collections ([], {})
Zero values (0, 0.0)
False boolean values
Example:
deftest_calculate_average_with_empty_list():
"""Test average calculation with empty list."""# Empty list should raise or return None (depending on design)with pytest.raises(ValueError, match="Cannot calculate average of empty list"):
calculate_average([])
deftest_get_user_by_email_with_none():
"""Test user lookup with None email."""with pytest.raises(ValidationError, match="Email cannot be None"):
get_user_by_email(None)
deftest_format_address_with_missing_fields():
"""Test address formatting with missing optional fields."""
address = {
"street": "123 Main St",
"city": "Springfield",
"state": None, # Optional field"zip": "", # Empty string
}
# Should handle missing fields gracefully
formatted = format_address(address)
assert"123 Main St"in formatted
assert"Springfield"in formatted
# Should not include state or zip if missingdeftest_divide_by_zero():
"""Test division with zero divisor."""with pytest.raises(ZeroDivisionError):
divide(10, 0)
Checklist for nullable inputs:
Test each nullable parameter with None
Test each string parameter with ""
Test each list parameter with []
Test each dict parameter with {}
Test each numeric parameter with 0
Category 4: ERROR CASES
Definition: Test when dependencies fail, resources are unavailable, or external calls raise exceptions.
Purpose: Verify error handling, logging, and graceful degradation.
What to test:
Database connection failures
Network timeouts
External API errors (4xx, 5xx)
File not found
Permission denied
Resource exhaustion (out of memory, disk full)
Invalid state transitions
Example:
deftest_save_user_when_database_unavailable(mocker):
"""Test user save handles DB connection failure gracefully."""# Mock database to raise connection error
mocker.patch.object(db, "save", side_effect=ConnectionError("DB unavailable"))
user = User(email="alice@example.com")
# Should raise specific error (not generic exception)with pytest.raises(DatabaseError, match="Failed to save user"):
save_user(user)
# Should log errorassert"DB unavailable"in captured_logs
deftest_fetch_user_when_api_returns_500(mocker):
"""Test user fetch handles API 500 error."""
mocker.patch("requests.get", return_value=MockResponse(status=500))
with pytest.raises(ExternalAPIError):
fetch_user_from_external_api("user123")
deftest_process_payment_when_gateway_timeout(mocker):
"""Test payment processing handles gateway timeout."""
mocker.patch.object(
payment_gateway,
"charge",
side_effect=TimeoutError("Gateway timeout"),
)
result = process_payment(amount=100, card_token="tok_123")
# Should return failure result (not raise)assert result.status == "failed"assert"timeout"in result.error.lower()
# Should not charge userassert payment_gateway.charge.call_count == 1# No retries on timeout
Common error scenarios:
Network failures (timeout, connection refused, DNS error)
If you can't test a category, explain why and how the risk is mitigated:
## Test Coverage for `process_payment()`
- [x] HAPPY PATH
- [x] ERROR CASES - Gateway timeout, card declined
- [ ] CONCURRENT - **GAP**: Concurrent payments from same user not tested
- **Mitigation**: Payment gateway handles idempotency
- **Risk**: Low (gateway prevents double-charge)
- **TODO**: Add test when we migrate to new gateway (Q3 2026)
Common Mistakes
❌ Mistake 1: Only Testing Happy Path
Problem: Tests pass with valid inputs but fail in production with edge cases.
Fix: Use this category framework to ensure comprehensive coverage.