This document provides comprehensive information about the test suite for Composer Update Helper, including tests for the new features implemented in Phase 1.
- Test Structure
- Running Tests
- Test Coverage
- New Feature Tests (Phase 1)
- Integration Tests
- Test Files Structure
- Writing New Tests
- Continuous Integration
- Coverage Requirements
- Debugging Tests
- Future Test Enhancements
The test suite is organized into several test classes:
DependencyCompatibilityTest.php: Tests for dependency compatibility checking, conflict detection, and new features (abandoned packages, fallback versions)InstallerTest.php: Tests for installation and migration functionalityPluginTest.php: Tests for Composer plugin integrationScriptTest.php: Tests for shell script functionality
# Run all tests
composer test
# Run tests with coverage
composer test-coverage
# Run tests with specific PHPUnit options
vendor/bin/phpunit# Run only dependency compatibility tests
vendor/bin/phpunit tests/DependencyCompatibilityTest.php
# Run with verbose output
vendor/bin/phpunit --verbose tests/DependencyCompatibilityTest.php
# Run specific test method
vendor/bin/phpunit --filter testIsPackageAbandoned tests/DependencyCompatibilityTest.phpThe test suite maintains ≥99% line coverage on src/ (REQ-TEST-003). Current coverage is 100%.
# Generate coverage report
composer test-coverage
# Open coverage report in browser
open coverage/index.html # macOS
xdg-open coverage/index.html # LinuxPurpose: Verify abandoned package detection logic.
What it tests:
- Function exists and is callable
- Graceful error handling when API is unavailable
- Integration with conflict detection flow
Test Data:
- Uses actual Packagist API structure
- Tests both abandoned and non-abandoned packages
Expected Behavior:
- Returns
nullon API errors (graceful degradation) - Returns array with
abandoned(bool) andreplacement(string|null) on success - Integrates correctly with conflict detection output
Purpose: Verify abandoned package detection with replacement package.
What it tests:
- Correct parsing of Packagist's
abandonedfield - Handling of replacement package information
- Handling of abandoned packages without replacements
Test Data:
$abandonedInfo = [
'abandoned' => true,
'replacement' => 'new/package-name'
];Expected Behavior:
- Correctly identifies abandoned status
- Extracts replacement package name when available
- Handles
nullreplacement gracefully
Purpose: Verify fallback version search logic.
What it tests:
- Version constraint satisfaction for fallback versions
- Correct identification of compatible older versions
- Rejection of incompatible versions
Test Scenario:
- Target version:
2.0.0 - Conflicting constraint:
^1.5 - Expected fallback:
1.9.5or similar (satisfies^1.5)
Test Cases:
- ✅
1.9.5satisfies^1.5(valid fallback) - ✅
1.8.0satisfies^1.5(valid fallback) - ✅
1.5.0satisfies^1.5(valid fallback) - ❌
2.0.0does NOT satisfy^1.5(needs fallback) - ❌
1.4.0does NOT satisfy^1.5(too old)
Expected Behavior:
- Correctly identifies versions that satisfy conflicting constraints
- Rejects versions that don't satisfy constraints
- Finds highest compatible version below target
Purpose: Verify fallback version satisfies ALL conflicting constraints.
What it tests:
- Handling multiple conflicting constraints
- Version must satisfy all constraints simultaneously
- Rejection if version satisfies only some constraints
Test Scenario:
- Constraint 1:
^1.5 - Constraint 2:
^1.6 - Expected fallback:
>= 1.6.0and< 2.0.0
Test Cases:
- ✅
1.6.5satisfies both^1.5and^1.6(valid fallback) - ❌
1.5.5satisfies^1.5but NOT^1.6(invalid fallback) - ❌
2.0.0satisfies neither (invalid fallback)
Expected Behavior:
- Fallback must satisfy ALL conflicting constraints
- Versions satisfying only some constraints are rejected
Purpose: Verify fallback versions are always older than target.
What it tests:
- Fallback version must be
< target version - Versions
>= targetare not valid fallbacks - Version comparison logic
Test Data:
- Target:
2.0.0 - Valid fallbacks:
1.9.9,1.8.0,1.5.0,1.0.0 - Invalid fallbacks:
2.0.0,2.0.1,3.0.0
Expected Behavior:
- Only versions less than target are considered
- Version comparison uses proper semver logic
Purpose: Verify fallback version search handles edge cases.
What it tests:
- Empty conflicting dependents (should not search)
- Descending version order (finds highest compatible first)
- No fallback found scenario
Test Cases:
- Empty conflicts array → no search performed
- Version sorting → descending order (highest first)
- No compatible version → returns
null
Expected Behavior:
- Graceful handling of edge cases
- Correct search order (highest compatible version first)
- Proper null handling when no fallback exists
To test abandoned package detection in the actual output:
- Use a known abandoned package (e.g.,
symfony/polyfill-php54) - Create a conflict scenario where the package is filtered
- Verify output contains abandoned warning
- Verify replacement package is shown if available
Example Test Command:
# Set up project with abandoned package
composer require symfony/polyfill-php54:^1.0
# Run update helper (should show abandoned warning)
./generate-composer-require.sh --debugTo test fallback version suggestions in the actual output:
- Set up a package with version history (e.g.,
doctrine/orm) - Create a conflict where newer version doesn't satisfy constraints
- Verify output contains "Alternative solutions" section
- Verify fallback version is shown and is compatible
Example Test Command:
# Set up project with conflicting dependencies
# Run update helper (should show fallback suggestions)
./generate-composer-require.sh --debugtests/
├── DependencyCompatibilityTest.php # New feature tests + existing compatibility tests
├── InstallerTest.php # Installation tests
├── PluginTest.php # Plugin integration tests
├── ScriptTest.php # Shell script tests
├── check-coverage.php # Coverage validation script
└── test-*.sh # Shell script tests
<?php
declare(strict_types=1);
namespace NowoTech\ComposerUpdateHelper\Tests;
use PHPUnit\Framework\TestCase;
final class DependencyCompatibilityTest extends TestCase
{
private string $tempDir;
protected function setUp(): void
{
$this->tempDir = sys_get_temp_dir() . '/composer-update-helper-test-' . uniqid();
mkdir($this->tempDir, 0777, true);
}
protected function tearDown(): void
{
$this->removeDirectory($this->tempDir);
}
public function testNewFeature(): void
{
// Arrange: Set up test data
// Act: Execute function being tested
// Assert: Verify expected behavior
$this->assertTrue($result);
}
}- Test methods must start with
testprefix - Use descriptive names:
testFeatureWithCondition() - Follow pattern:
testWhatIsBeingTestedUnderWhatConditions()
- Isolation: Each test should be independent
- Cleanup: Use
tearDown()to clean temporary files - Assertions: Use specific assertions (
assertEqualsvsassertTrue) - Documentation: Add PHPDoc explaining what the test verifies
- Coverage: Aim for 100% coverage of new code
Tests run automatically on every push via GitHub Actions:
- ✅ PHP 7.4, 8.0, 8.1, 8.2, 8.3
- ✅ Code coverage report (99% minimum required)
- ✅ Code style checks (PSR-12)
- ✅ All tests must pass before merge
- Minimum: 99% code coverage
- Current: 99.20% (exceeds minimum)
- Enforcement: CI/CD pipeline fails if coverage drops below 99%
vendor/bin/phpunit --verbosevendor/bin/phpunit --stop-on-failure# Run with PHP debugger
php -dxdebug.mode=debug vendor/bin/phpunit --filter testNamePlanned improvements to the test suite:
- Mocked API calls: Mock Packagist API responses for faster, more reliable tests
- Integration test suite: Full end-to-end tests with real Composer projects
- Performance tests: Verify API calls are efficient and cached
- Edge case coverage: Additional tests for unusual scenarios
Last updated: 2026-01-16 Document version: 1.0