Skip to content

boundwize/pyrameter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

40 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Pyrameter

Pyrameter

Keep your PHPUnit test suite shaped like a pyramid.

Latest Version ci build Code Coverage PHPStan Downloads

Windows macOS Linux

Pyrameter is a PHPUnit extension that shows what your test suite is becoming. It classifies each test by the classes and namespaces the test file consumes, then prints a shape report after PHPUnit runs.

Use it to spot a suite that is getting heavier, agree on what "healthy" means for your project, and optionally fail CI when the pyramid drifts too far.

vendor/bin/phpunit
........................
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.6%   <=  2.0%    βœ“

Total: 60 tests

Your suite is getting heavier.

How it works

Pyrameter does not trust test directories, and it does not scan production classes. Instead, it classifies by configured class or namespace usage in test files:

  • no configured heavy usage => unit
  • framework test runtime => functional
  • real resource boundary, such as database, cache, queue, filesystem, or external service => integration
  • browser driver usage => e2e

When multiple usages match, the heaviest kind wins. Mocked heavy dependencies stay unit.

Your pyramid, your rules: decide which class usage means functional or integration in your project, then configure Pyrameter to match your team's belief.

For example, if a test consumes an analyser that reads real paths, configure that analyser class or namespace as integration.

Quick start

Pyrameter supports PHP 8.2+ and PHPUnit 11 or 12.

Install it as a dev dependency:

composer require --dev boundwize/pyrameter

Register the PHPUnit extension:

<extensions>
    <bootstrap class="Boundwize\Pyrameter\Extension"/>
</extensions>

Run PHPUnit as usual:

vendor/bin/phpunit

If the config parameter is omitted, Pyrameter looks for pyrameter.php in the current working directory. If the file does not exist, it uses the default rules and target shape.

Configure

Create pyrameter.php when you want to tune the rules or targets.

Start with defaults() to keep Pyrameter's built-in rules for PDO, mysqli, Doctrine, Redis, Symfony functional tests, Panther, and WebDriver, then add your project-specific beliefs:

<?php

declare(strict_types=1);

use Boundwize\Pyrameter\Config\PyrameterConfig;
use Boundwize\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. It starts with no usage rules and no target shape:

<?php

declare(strict_types=1);

use Boundwize\Pyrameter\Config\PyrameterConfig;
use Boundwize\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],
    );

Targets are percentage ranges. Missing min means 0; missing max means 100. When targetShape() is called, missing kinds default to ['min' => 0, 'max' => 100], which Pyrameter reports as no target.

Fail CI

By default, Pyrameter is report-only. It prints target violations without changing PHPUnit's exit code.

Turn violations into a failing PHPUnit process when you are ready to enforce the shape:

return PyrameterConfig::defaults()
    ->failOnViolation();

A note on taxonomy

Pyrameter measures suite shape from static usage rules in test files. It is a useful pressure gauge, not a perfect taxonomy judge.

About

πŸ“ PHPUnit extension that measures the shape of your test suite

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors

Languages