testo / testo
A lightweight PHP testing framework.
Fund package maintenance!
0.10.1
2026-03-22 16:10 UTC
Requires
- php: >=8.2
- internal/destroy: ^1.0
- internal/path: ^1.2
- psr/container: 1 - 2
- psr/event-dispatcher: ^1.0
- symfony/console: ^6.4 || ^7 || ^8.0
- symfony/finder: ^6.4 || ^7 || ^8.0
- yiisoft/injector: ^1.2
Requires (Dev)
- buggregator/trap: ^1.10
- internal/dload: ^1.6
- roxblnfk/unpoly: ^1.8.2
- spiral/code-style: ^2.2.2
- vimeo/psalm: ^7.0@dev
Replaces
- internal/container: *
README
The PHP Testing Framework You Control
Testo is an extensible testing framework built on a lightweight core with a middleware system. It gives you full control over your testing environment while keeping the familiar PHP syntax you already know.
Get Started
Installation
composer require --dev testo/testo *
Configuration
By default, if no configuration file is provided, Testo will run tests from the tests folder.
To customize the configuration, create a testo.php file in the root of your project:
<?php declare(strict_types=1); use Testo\Application\Config\ApplicationConfig; use Testo\Application\Config\FinderConfig; use Testo\Application\Config\Plugin\SuitePlugins; use Testo\Application\Config\SuiteConfig; use Testo\Assert\AssertPlugin; use Testo\Bench\BenchmarkPlugin; use Testo\Inline\InlineTestPlugin; return new ApplicationConfig( suites: [ new SuiteConfig( name: 'Sources', location: ['src'], // Only Benchmarking and Inline Tests for Source files plugins: SuitePlugins::only( new InlineTestPlugin(), new BenchmarkPlugin(), new AssertPlugin(), ), ), new SuiteConfig( name: 'Unit', location: ['tests'], ), ], );
Running Tests
To run your tests, execute:
vendor/bin/testo
Writing Your First Test
Create a test class in the configured test directory (e.g., tests/CalculatorTest.php):
<?php declare(strict_types=1); namespace Tests; use Testo\Assert; use Testo\Assert\ExpectException; use Testo\Retry; use Testo\Test; final class CalculatorTest { #[Test] public function dividesNumbers(): void { $result = 10 / 2; Assert::same($result, 5.0); Assert::notSame($result, 5); // Types matter! } #[Test] #[Retry(maxAttempts: 3)] public function flakyApiCall(): void { // Retries up to 3 times if test fails $response = $this->makeExternalApiCall(); Assert::same($response->status, 200); } #[Test] #[ExpectException(\RuntimeException::class)] public function throwsException(): void { throw new \RuntimeException('Expected error'); } }
What to note:
- Use the
#[Test]attribute to mark test methods - Test classes don't need to extend any base class
- Use
Assertclass for assertions (same,true,false,null,contains,instanceOf, etc.) - Testo provides multiple attributes to extend testing capabilities (retry policies, exception handling, and more)
IDE Support
Testo comes with the IDEA plugin Testo.