Full Changelog: https://github.com/boundwize/pyrameter/compare/0.5.0...0.5.1
Pyrameter can now be selectively disabled without removing it from phpunit.xml or disabling other PHPUnit extensions:
PYRAMETER_DISABLED=1 vendor/bin/phpunit
When disabled, Pyrameter registers no subscribers, performs no measurements, prints no report, and does not enforce target violations.
PYRAMETER_DISABLED environment variable opt-out by @samsonasik in https://github.com/boundwize/pyrameter/pull/46Full Changelog: [0.4.4...0.5.0](https://github.com/boundwize/pyrameter/compare/0.4.4...0.5.0)
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.4.3...0.4.4
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.4.2...0.4.3
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.4.1...0.4.2
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.4.0...0.4.1
This release support PHPUnit ^13.
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.9...0.4.0
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.8...0.3.9
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.7...0.3.8
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.6...0.3.7
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.5...0.3.6
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.4...0.3.5
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.3...0.3.4
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.2...0.3.3
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.1...0.3.2
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.3.0...0.3.1
This release adds function-call based usage detection. You can now use usesFunction() in pyrameter.php to classify tests when they call project-specific or boundary-crossing functions.
// ...
->usesFunction('app_writes_to_disk', TestKind::Integration)
Pyrameter’s defaults now also treat common PHP filesystem functions as Integration, so tests using operations like file_get_contents(), file_put_contents(), fopen(), mkdir(), rename(), unlink(), glob(), and related file/directory functions are detected as integration tests automatically.
usesFunction() and default filesystem integration rules by @samsonasik in https://github.com/boundwize/pyrameter/pull/24Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.8...0.3.0
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.7...0.2.8
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.6...0.2.7
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.5...0.2.6
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.4...0.2.5
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.3...0.2.4
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.2...0.2.3
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.1...0.2.2
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.2.0...0.2.1
This release removes the Unknown type. Tests that cannot be inspected now fall back to Unit, making the reported shape easier to understand and verify.
This also show the pyramid visualization:
➜ pyrameter git:(main) vendor/bin/phpunit
PHPUnit 12.5.30 by Sebastian Bergmann and contributors.
Runtime: PHP 8.4.21
Configuration: /Users/samsonasik/www/boundwize/pyrameter/phpunit.xml
............................................................ 60 / 60 (100%)
Pyrameter
=========
Shape: Healthy Pyramid
Result: Passed ✓
╭───────╮
│ E2E ✓ │
╭─────┴───────┴─────╮
│ Integration ✓ │
╭────┴───────────────────┴────╮
│ Functional ✓ │
╭──────┴─────────────────────────────┴──────╮
│ Unit ✓ │
╰───────────────────────────────────────────╯
Kind Tests Actual Target Status
Unit 37 78.7% >= 60.0% ✓
Functional 6 12.8% <= 20.0% ✓
Integration 4 8.5% <= 16.0% ✓
E2E 0 0.0% <= 2.0% ✓
Total: 47 tests
Your test pyramid target passed.
Time: 00:00.412, Memory: 26.00 MB
OK (60 tests, 145 assertions)
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.1.2...0.2.0
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.1.1...0.1.2
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.1.0...0.1.1
This Release change Pyrameter namespace to Boundwize\Pyrameter for consistency.
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.0.2...0.1.0
Full Changelog: https://github.com/boundwize/pyrameter/compare/0.0.1...0.0.2
It classifies tests by the classes and namespaces each test file consumes, then prints a pyramid shape report after PHPUnit runs.
Use it to spot when your suite is getting heavier, agree on what "healthy" means for your project, and optionally fail CI when the pyramid drifts too far.
composer require --dev boundwize/pyrameter
Register the PHPUnit extension:
<extensions>
<bootstrap class="Pyrameter\Extension"/>
</extensions>
Then run PHPUnit as usual:
vendor/bin/phpunit
After the test run, Pyrameter prints a summary of your suite shape:
Pyrameter
=========
Shape: Integration Mountain
Result: Violated ⚠
Kind Tests Actual Target Status
Unit 39 65.0% >= 70.0% ✗
Functional 10 16.7% <= 20.0% ✓
Integration 9 15.0% <= 8.0% ✗
E2E 1 1.7% <= 2.0% ✓
Unknown 1 1.7% <= 2.0% ✓
Total: 60 tests
Your suite is getting heavier.
Pyrameter does not trust test directories.
It does not scan production classes.
Instead, it classifies tests by configured class or namespace usage in test files:
When multiple usages match, the heaviest kind wins.
Mocked heavy dependencies stay unit.
If no config path is provided, Pyrameter looks for pyrameter.php in the current working directory.
Start with defaults() to keep the built-in rules for common heavy usage, then tune the target shape for your project:
<?php
declare(strict_types=1);
use Pyrameter\Config\PyrameterConfig;
use Pyrameter\TestKind;
return PyrameterConfig::defaults()
->usesClass(App\Analyser\Analyser::class, TestKind::Integration)
->usesNamespace('App\Tests\Browser\\', TestKind::E2E)
->targetShape(
unit: ['min' => 75],
functional: ['max' => 15],
integration: ['max' => 7],
e2e: ['max' => 2],
unknown: ['max' => 1],
);
Use create() when you want full control with no built-in usage rules:
<?php
declare(strict_types=1);
use Pyrameter\Config\PyrameterConfig;
use Pyrameter\TestKind;
return PyrameterConfig::create()
->usesClass(PDO::class, TestKind::Integration)
->usesNamespace('Doctrine\DBAL\\', TestKind::Integration)
->usesNamespace('Symfony\Bundle\FrameworkBundle\Test\\', TestKind::Functional)
->usesNamespace('Symfony\Component\Panther\\', TestKind::E2E)
->usesNamespace('Facebook\WebDriver\\', TestKind::E2E)
->targetShape(
unit: ['min' => 70],
functional: ['max' => 18],
integration: ['max' => 8],
e2e: ['max' => 2],
unknown: ['max' => 2],
);
By default, Pyrameter is report-only.
It prints target violations without changing PHPUnit's exit code.
When you are ready to enforce the shape in CI:
return PyrameterConfig::defaults()
->failOnViolation();
Pyrameter supports PHP 8.2+ and PHPUnit 11 or 12.
This is an early 0.0.1 release. The API should be considered unstable — breaking changes may occur in minor versions before 1.0.0.
Feedback, issues, and contributions are very welcome at https://github.com/boundwize/pyrameter
How can I help you explore Laravel packages today?