A parallel-first testing framework for PHP.
Greenlight discovers your suite once and schedules its test classes across a worker pool for parallel execution by default.
composer require --dev greenlight/greenlight vendor/bin/greenlightRunning38 / 802 tests11 workers
Acceptance\WorkerProcessRunTest43.302sAcceptance\CliTest53.302sAcceptance\PhpStanMatcherSignatureTest03.297sAcceptance\SymfonyRunTest00.762s
… and 3 more running
Use every available coreThe runner executes test classes in parallel.
Use plain PHP testsTests need no base class or method-name convention.
Use your current toolsTyped APIs work with your IDE and PHPStan.
Write a test
Tests stay plain PHP.
Use ordinary classes, native attributes, and typed expectations. Greenlight finds each #[Test] method without a base class or method-name convention.
<?php
use Greenlight\Attribute\DataRow;
use Greenlight\Attribute\Test;
use Greenlight\Expect\Expect;
final class PriceTest
{
#[Test]
#[DataRow(['9.99', 2, '19.98'])]
public function multipliesLineTotals(
string $unit,
int $quantity,
string $expected,
): void {
$total = Price::fromString($unit)->times($quantity);
Expect::that($total->format())->toBe($expected);
}
}Run the suite
Greenlight manages the worker pool for you.
- 01
Run one command
Greenlight discovers the suite once and builds the execution plan.
- 02
Keep every worker busy
The orchestrator assigns one scheduling unit to each available worker. Greenlight starts known slow classes and previously failed classes early.
- 03
Read one clear result
Greenlight checks every worker result and prints one ordered report.
Test failures
Failures stay contained and readable.
Crashed workerThe orchestrator returns the rest of the assignment to the queue and starts a replacement worker.
Hung testA hard timeout stops the worker. A replacement worker continues the suite.
External resourcesUse channels to select separate resources for each worker. Resource limits restrict concurrent access to shared dependencies.
Missed mock callWhen the test ends, Greenlight verifies strict doubles and reports unmet expectations.
❯ vendor/bin/greenlightGreenlight dev-mainPHP 8.4.14 | configuration: greenlight.php | workers: 11 | seed: 560647545− Unit\Coverage\XdebugDriverTest (1 test, skipped, 0.002s)802 tests, 801 passed, 1 skipped, 2797 expectationsTime: 10.341sWorkers: 11 spawnedSkipped: XdebugDriverTest::collectsRealLineCoverageOverTheFixture (xdebug with coverage mode is not available)Slowest tests: 4.187s PhpStanToThrowRuleTest::patternAndExactMessageConstraints… 4.174s PhpStanMatcherSignatureTest::reflectedMatcherSignatures… 3.908s PhpStanDataProviderShapeRuleTest::providerAndRowShapes…Move from PHPUnit
Move one test class at a time.
Greenlight changes the test support code but does not change the code under test. Start with one small test class that has few dependencies. Run it with one worker. After it passes, enable parallel execution.
Read the PHPUnit migration guideextends TestCase- plain class
test*()#[Test]on a public method$this->assertSame()Expect::that()->toBe()createMock()- injected strict
Doubles
Try one test class
Go from installation to your first run.
Before you change the rest of your suite, run one test class successfully.
- 01
Install Greenlight
composer require --dev greenlight/greenlight - 02
Add
greenlight.php<?php return GreenlightConfig::create(); - 03
Run one class
vendor/bin/greenlight run --filter=PriceTest