Test Coverage Analysis
Analyzes PHP codebase to identify untested code and coverage gaps.
Detection Patterns
1. Classes Without Tests
bash
# Find all PHP classes in src/ Glob: src/**/*.php # Find all test files Glob: tests/**/*Test.php # Compare: class Foo in src/ should have FooTest in tests/
Pattern Matching:
code
src/Domain/User/User.php → tests/Unit/Domain/User/UserTest.php src/Application/PlaceOrder/PlaceOrderHandler.php → tests/Unit/Application/PlaceOrder/PlaceOrderHandlerTest.php
2. Methods Without Tests
php
// For each public method in class Grep: "public function [a-z]" --glob "src/**/*.php" // Check if test method exists Grep: "test_methodName" --glob "tests/**/*Test.php"
Detection Logic:
code
Class: Order ├── confirm() → test_confirm_* exists? ✅/❌ ├── cancel() → test_cancel_* exists? ✅/❌ ├── ship() → test_ship_* exists? ✅/❌ └── addItem() → test_addItem_* / test_add_item_* exists? ✅/❌
3. Branches Not Covered
If/Else Branches:
php
// Source code
public function process(Order $order): void
{
if ($order->isPending()) { // Branch 1: pending
$this->processPending($order);
} elseif ($order->isConfirmed()) { // Branch 2: confirmed
$this->processConfirmed($order);
} else { // Branch 3: other
throw new InvalidStateException();
}
}
// Required tests:
// - test_process_when_pending_*
// - test_process_when_confirmed_*
// - test_process_when_other_throws_exception
Switch Statements:
php
// Source code
match ($status) {
'pending' => $this->handlePending(),
'confirmed' => $this->handleConfirmed(),
'shipped' => $this->handleShipped(),
default => throw new UnexpectedValueException(),
};
// Required tests: one per case + default
4. Exception Paths
php
// Detect throw statements Grep: "throw new" --glob "src/**/*.php" // Each throw should have corresponding test with expectException
Example:
php
// Source
public function withdraw(Money $amount): void
{
if ($amount->greaterThan($this->balance)) {
throw new InsufficientFundsException(); // Line 15
}
}
// Required test
public function test_withdraw_throws_for_insufficient_funds(): void
{
$this->expectException(InsufficientFundsException::class);
// ...
}
5. Edge Cases
| Type | Values to Test | Detection |
|---|---|---|
| Null | null input | Parameters without type hint or nullable |
| Empty | [], '', 0 | Collection/string/numeric parameters |
| Boundary | min, max, min-1, max+1 | Constants, validation limits |
| Unicode | 'émoji 🎉' | String parameters |
| Concurrent | Race conditions | Shared state, repositories |
Detection Patterns:
php
// Nullable parameters Grep: "\?[A-Z]" --glob "src/**/*.php" // ?Type Grep: "null\|" --glob "src/**/*.php" // Type|null // Collections Grep: "array \$" --glob "src/**/*.php" Grep: "iterable" --glob "src/**/*.php" // Numeric limits Grep: "const MAX_" --glob "src/**/*.php" Grep: "const MIN_" --glob "src/**/*.php"
Analysis Process
Phase 1: Inventory
- •
List all production classes:
codeGlob: src/**/*.php
- •
List all test classes:
codeGlob: tests/**/*Test.php
- •
Build mapping:
codeProductionClass → [TestClass, TestClass]
Phase 2: Class Coverage
For each production class:
- •Check if corresponding test exists
- •Calculate:
covered_classes / total_classes * 100
Phase 3: Method Coverage
For each public method:
- •Extract method names from production code
- •Search for
test_{method}patterns in tests - •Calculate:
tested_methods / total_methods * 100
Phase 4: Branch Coverage
For each conditional:
- •Count branches (if/elseif/else, match cases)
- •Search for tests covering each branch
- •Report uncovered branches
Phase 5: Edge Cases
- •Identify nullable/optional parameters
- •Identify collections
- •Identify numeric limits
- •Check if edge case tests exist
Output Format
markdown
# Test Coverage Analysis Report ## Summary | Metric | Value | Target | |--------|-------|--------| | Class Coverage | 75% | 90% | | Method Coverage | 60% | 80% | | Branch Coverage | 45% | 70% | ## Untested Classes | Class | Location | Priority | |-------|----------|----------| | `PaymentProcessor` | src/Domain/Payment/ | High | | `EmailNotifier` | src/Infrastructure/ | Medium | ## Untested Methods | Class | Method | Reason | |-------|--------|--------| | `Order` | `splitShipment()` | No test found | | `User` | `resetPassword()` | Only happy path tested | ## Uncovered Branches | File | Line | Branch | Missing Test | |------|------|--------|--------------| | Order.php | 45 | else (cancelled) | test_ship_when_cancelled | | User.php | 23 | null check | test_with_null_email | ## Missing Edge Cases | Class | Method | Edge Case | |-------|--------|-----------| | `Cart` | `addItem()` | Empty cart, max items | | `Money` | `add()` | Zero amount, overflow | ## Action Items ### Critical (Must Have) 1. Add `PaymentProcessorTest` — handles money 2. Add `test_order_ship_when_cancelled` — business rule ### High Priority 1. Add null checks for `User::resetPassword()` 2. Add boundary tests for `Cart::addItem()` ### Recommended Skills | Gap | Skill | Action | |-----|-------|--------| | Missing unit test | `acc-create-unit-test` | Generate test class | | Missing integration test | `acc-create-integration-test` | Generate DB test | | Need test data | `acc-create-test-builder` | Generate builder |
Severity Levels
| Level | Coverage | Action |
|---|---|---|
| Critical | <50% | Immediate attention |
| Warning | 50-70% | Prioritize improvement |
| Good | 70-90% | Monitor and maintain |
| Excellent | >90% | Focus on edge cases |
Integration with Generator
After analysis, recommend using:
- •
acc-create-unit-test— for missing unit tests - •
acc-create-integration-test— for missing integration tests - •
acc-create-test-builder— for complex test data - •
acc-create-mock-repository— for repository tests