Development utilities for PHPStan rules testing, extracted from shipmonk/phpstan-rules.
This package provides the RuleTestCase
class - an enhanced testing framework specifically designed for testing PHPStan rules with additional validation and convenience features.
composer require --dev shipmonk/phpstan-dev
<?php declare(strict_types = 1);
namespace YourNamespace;
use ShipMonk\PHPStanDev\RuleTestCase;
use PHPStan\Rules\Rule;
/**
* @extends RuleTestCase<YourRule>
*/
class YourRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
return new YourRule();
}
public function testRule(): void
{
$this->analyzeFiles([__DIR__ . '/Data/YourRule/code.php']);
}
}
Create tests/Rule/Data/YourRule/code.php
:
<?php declare(strict_types = 1);
namespace YourRule;
function test() {
$valid = 'This is valid code';
$invalid = something(); // error: Your custom error message here
}
vendor/bin/phpunit tests/Rule/YourRuleTest.php
Use // error: <message>
comments in test files to specify expected errors:
<?php
$validCode = 'No error expected here';
$invalidCode = forbidden(); // error: This is forbidden
$alsoInvalid = another(); // error: Another error message
During development, automatically generate error comments:
public function testRule(): void
{
// Set to true temporarily to generate error comments
$this->analyzeFiles([__DIR__ . '/Data/code.php'], autofix: true);
}
autofix: true
before committing - tests will fail if autofix is enabled.
Every error is automatically validated:
- ✅ Must have an identifier
- ✅ Errors are matched to specific line numbers
class ComplexRuleTest extends RuleTestCase
{
private bool $strictMode = false;
protected function getRule(): Rule
{
return new ComplexRule($this->strictMode);
}
public function testDefault(): void
{
$this->analyzeFiles([__DIR__ . '/Data/ComplexRule/default.php']);
}
public function testStrict(): void
{
$this->strictMode = true;
$this->analyzeFiles([__DIR__ . '/Data/ComplexRule/strict.php']);
}
}
public function testPhp82Features(): void
{
$this->phpVersion = $this->createPhpVersion(80_200);
$this->analyzeFiles([__DIR__ . '/Data/Rule/php82-features.php']);
}
Create tests/Rule/Data/YourRule/config.neon
:
parameters:
customParameter: value
Then reference it in your test:
public static function getAdditionalConfigFiles(): array
{
return array_merge(
parent::getAdditionalConfigFiles(),
[__DIR__ . '/Data/YourRule/config.neon'],
);
}
protected function getRule(): Rule
{
$dependency = self::getContainer()->getByType(SomeService::class);
return new RuleWithDependencies($dependency);
}
Recommended directory structure:
tests/
├── Rule/
│ ├── YourRuleTest.php
│ ├── AnotherRuleTest.php
│ └── Data/
│ ├── YourRule/
│ │ ├── code.php # Main test file
│ │ ├── edge-cases.php # Additional scenarios
│ │ └── config.neon # Optional PHPStan config
│ └── AnotherRule/
│ └── code.php
# Install dependencies
composer install
# Run all checks
composer check
# Individual checks
composer check:composer # Validate composer.json
composer check:ec # Check EditorConfig compliance
composer check:cs # Check coding standards (PHPCS)
composer check:types # Run PHPStan analysis
composer check:dependencies # Analyze dependencies
composer check:collisions # Check for name collisions
# Fix coding standards
composer fix:cs
MIT License - see LICENSE file.