cruciblephp / crucible
Crucible PHP — an independent, XML-free testing framework for PHP 8.3+, drop-in compatible with PHPUnit suites and built for Laravel.
Fund package maintenance!
Requires
- php: >=8.3
- ext-dom: *
- ext-mbstring: *
- ext-simplexml: *
Requires (Dev)
- justinrainbow/json-schema: ^6.0
- laravel/pint: ^1.29
- phpstan/phpstan: ^2.2
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- rector/rector: ^2.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Crucible PHP
An independent, XML-free test framework for PHP 8.3+ — drop-in compatible with PHPUnit suites, engineered like the best runners of other ecosystems.
composer require --dev cruciblephp/crucible ./vendor/bin/crucible --init ./vendor/bin/crucible
And when it finishes — where the time went, in columns, with the verdict last:
On a real Pest 5 suite, faster than Pest itself — same 1,926 tests, same machine, alternated
runs; method and raw times in benchmarks/manifest.json:
Already have a phpunit.xml? ./vendor/bin/crucible migrate-config converts it, and tells you
about anything it could not translate rather than dropping it silently.
Requirements
PHP 8.3 or newer, and nothing else. No runtime dependencies — the extensions below ship with a stock PHP build.
| PHP | >= 8.3 |
| Extensions | ext-dom, ext-mbstring, ext-simplexml |
| Composer dependencies | none |
| Optional | ext-xdebug or ext-pcov for coverage · Node for the browser tier |
The floor is deliberate: a suite on 8.3 should not have to move the whole project to a newer PHP to change test runner.
Start here
./vendor/bin/crucible manual
The whole manual, in the terminal: ↑/↓ to scroll, / to search, number keys to follow a link,
⌫ to go back, q to quit. Piped or in CI it prints the same text plainly.
./vendor/bin/crucible manual --out=manual.pdf # the same text, as a PDF eval "$(./vendor/bin/crucible completion bash)" # tab completion: bash, zsh or fish
Everything below is a summary. The manual is the real document.
Three dialects, one run
// PHPUnit — your existing suite, unchanged. final class CalculatorTest extends TestCase { public function testAddsTwoNumbers(): void { $this->assertSame(4, 2 + 2); } } // Pest — *.pest.php, natively. it('rounds up', fn() => expect((int) ceil(1.2))->toBe(2)); // Architecture is a test, not a linter. arch('the domain stays pure')->expect('App\Domain')->toOnlyUse('App\Domain'); // The browser is a first-class tier: the server runs inside the test // process, so whatever the test faked is what the page sees. visit('/checkout')->click('Place order')->waitForNetworkIdle()->assertSee('Thank you');
Every sample is from examples/, and those files are run by the test suite —
an example that stopped working turns the suite red.
Documentation
crucible manual |
All of it, in the terminal |
| MANUAL.md | The same document, on the web |
| HELP.md | Every command-line option |
| examples/ | Executable examples, run by the suite |
| RELEASE.md | What shipped, traced to its decision record |
| DESIGN.md | Why each thing is the way it is |
| ORACLES.md | The real installs some tests run against, and how to rebuild them |
The idea
Spec, not source. Crucible is a clean-room implementation. PHPUnit defines the behavioral spec — assertions, attributes, CLI options, defaults, exit codes — established from public documentation and black-box observation of the binary, never read as source. No code, templates, doc comments, or message text are copied from any project.
Compatibility is executable, not claimed. 19 fixture suites run against both the real
phpunit binary and crucible, asserting identical outcomes, sequences, counts, issue tallies
and exit codes. Every machine-readable report — Clover, Cobertura, Crap4J, JUnit, TeamCity,
coverage XML — is compared against the incumbent's own writer too, by structure and by the
numbers inside it.
If it can be done better, do it better. A versioned NDJSON event stream as the single output substrate, supervisor/worker execution where that stream is the IPC, duration-aware and defects-first scheduling, VMVM-style state isolation, Ekstazi-style impact selection.
DESIGN.md has the reasoning, decision by decision.
The code is MIT. The name "Crucible" and the Crucible logo are trademarks of Luciano Federico Pereira and are not covered by that licence — see LICENSE. Fork the software freely; do not ship it under this name or mark.
© 2026 Luciano Federico Pereira · cruciblephp.com